#!/bin/bash

# Secure Deployment Script for Portfolio Tracker
# This script deploys the application with all security features enabled

set -e

ENVIRONMENT="${1:-production}"
DOMAIN="${2:-localhost}"
DEPLOY_DIR="${DEPLOY_DIR:-/opt/portfolio-tracker}"
BACKUP_DIR="${BACKUP_DIR:-/opt/portfolio-tracker/backups}"
LOG_DIR="${LOG_DIR:-/var/log/portfolio-tracker}"

echo "🚀 Starting secure deployment for Portfolio Tracker"
echo "Environment: $ENVIRONMENT"
echo "Domain: $DOMAIN"
echo "Deploy Directory: $DEPLOY_DIR"

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

# Function to print colored output
print_status() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

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

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

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

# Function to check if command exists
command_exists() {
    command -v "$1" >/dev/null 2>&1
}

# Function to generate secure random string
generate_secret() {
    openssl rand -base64 32
}

# Pre-deployment checks
print_step "Running pre-deployment checks..."

# Check required commands
required_commands=("node" "npm" "docker" "openssl" "jq")
for cmd in "${required_commands[@]}"; do
    if ! command_exists "$cmd"; then
        print_error "Required command '$cmd' not found. Please install it first."
        exit 1
    fi
done

print_status "All required commands are available"

# Check Node.js version
NODE_VERSION=$(node --version | cut -d'v' -f2)
REQUIRED_NODE_VERSION="18.0.0"

if ! node -e "process.exit(require('semver').gte('$NODE_VERSION', '$REQUIRED_NODE_VERSION') ? 0 : 1)" 2>/dev/null; then
    print_error "Node.js version $NODE_VERSION is not supported. Please upgrade to $REQUIRED_NODE_VERSION or higher."
    exit 1
fi

print_status "Node.js version $NODE_VERSION is supported"

# Create necessary directories
print_step "Creating deployment directories..."

sudo mkdir -p "$DEPLOY_DIR"
sudo mkdir -p "$BACKUP_DIR"
sudo mkdir -p "$LOG_DIR"
sudo mkdir -p "$DEPLOY_DIR/certs"
sudo mkdir -p "$DEPLOY_DIR/config"

print_status "Deployment directories created"

# Backup existing deployment if it exists
if [ -d "$DEPLOY_DIR/current" ]; then
    print_step "Creating backup of existing deployment..."
    
    BACKUP_NAME="backup-$(date +%Y%m%d_%H%M%S)"
    sudo cp -r "$DEPLOY_DIR/current" "$BACKUP_DIR/$BACKUP_NAME"
    
    print_status "Backup created: $BACKUP_DIR/$BACKUP_NAME"
fi

# Build the application
print_step "Building application..."

npm run build
if [ $? -ne 0 ]; then
    print_error "Build failed"
    exit 1
fi

print_status "Application built successfully"

# Run security tests
print_step "Running security tests..."

if [ -f "./scripts/security-audit.sh" ]; then
    chmod +x ./scripts/security-audit.sh
    
    # Run security audit in test mode
    API_BASE_URL="http://localhost:3000" ./scripts/security-audit.sh || {
        print_warning "Security audit found issues. Review the results before proceeding."
        read -p "Continue with deployment? (y/N): " -n 1 -r
        echo
        if [[ ! $REPLY =~ ^[Yy]$ ]]; then
            print_error "Deployment cancelled"
            exit 1
        fi
    }
else
    print_warning "Security audit script not found, skipping security tests"
fi

# Generate SSL certificates
print_step "Setting up SSL certificates..."

if [ "$ENVIRONMENT" = "production" ]; then
    if [ "$DOMAIN" != "localhost" ]; then
        # Production: Use Let's Encrypt
        print_status "Setting up Let's Encrypt certificates for $DOMAIN"
        
        if command_exists certbot; then
            sudo certbot certonly --standalone -d "$DOMAIN" --non-interactive --agree-tos --email "admin@$DOMAIN" || {
                print_error "Failed to generate Let's Encrypt certificate"
                exit 1
            }
            
            # Copy certificates to deployment directory
            sudo cp "/etc/letsencrypt/live/$DOMAIN/privkey.pem" "$DEPLOY_DIR/certs/key.pem"
            sudo cp "/etc/letsencrypt/live/$DOMAIN/fullchain.pem" "$DEPLOY_DIR/certs/cert.pem"
            
            print_status "Let's Encrypt certificates configured"
        else
            print_error "certbot not found. Please install certbot for SSL certificate generation."
            exit 1
        fi
    else
        print_warning "Using localhost in production. This is not recommended."
    fi
else
    # Development/Staging: Generate self-signed certificates
    print_status "Generating self-signed certificates for development"
    
    if [ -f "./scripts/generate-ssl-certs.sh" ]; then
        SSL_DOMAIN="$DOMAIN" ./scripts/generate-ssl-certs.sh
        sudo cp ./certs/* "$DEPLOY_DIR/certs/"
    else
        print_error "SSL certificate generation script not found"
        exit 1
    fi
fi

# Generate environment configuration
print_step "Generating environment configuration..."

ENV_FILE="$DEPLOY_DIR/config/.env.$ENVIRONMENT"

if [ ! -f "$ENV_FILE" ]; then
    print_status "Creating new environment configuration"
    
    # Copy template
    cp ".env.$ENVIRONMENT.example" "$ENV_FILE" 2>/dev/null || {
        print_warning "Environment template not found, creating basic configuration"
        cat > "$ENV_FILE" << EOF
NODE_ENV=$ENVIRONMENT
HTTPS_ENABLED=true
HTTPS_KEY_PATH=$DEPLOY_DIR/certs/key.pem
HTTPS_CERT_PATH=$DEPLOY_DIR/certs/cert.pem
EOF
    }
    
    # Generate secure secrets
    JWT_ACCESS_SECRET=$(generate_secret)
    JWT_REFRESH_SECRET=$(generate_secret)
    INTERNAL_API_TOKEN=$(generate_secret)
    
    # Update secrets in environment file
    sed -i "s/your-super-secure-access-secret-here-min-32-chars/$JWT_ACCESS_SECRET/g" "$ENV_FILE"
    sed -i "s/your-super-secure-refresh-secret-here-min-32-chars/$JWT_REFRESH_SECRET/g" "$ENV_FILE"
    sed -i "s/your-internal-api-token-here/$INTERNAL_API_TOKEN/g" "$ENV_FILE"
    
    print_status "Environment configuration created with secure secrets"
    print_warning "Please review and update $ENV_FILE with your specific configuration"
else
    print_status "Using existing environment configuration: $ENV_FILE"
fi

# Set secure file permissions
print_step "Setting secure file permissions..."

sudo chmod 600 "$DEPLOY_DIR/certs/key.pem" 2>/dev/null || true
sudo chmod 644 "$DEPLOY_DIR/certs/cert.pem" 2>/dev/null || true
sudo chmod 600 "$ENV_FILE"
sudo chown -R root:root "$DEPLOY_DIR/certs"
sudo chown root:root "$ENV_FILE"

print_status "Secure file permissions set"

# Deploy application files
print_step "Deploying application files..."

# Create new deployment directory
DEPLOY_TIMESTAMP=$(date +%Y%m%d_%H%M%S)
NEW_DEPLOY_DIR="$DEPLOY_DIR/releases/$DEPLOY_TIMESTAMP"

sudo mkdir -p "$NEW_DEPLOY_DIR"

# Copy built application
sudo cp -r ./dist/* "$NEW_DEPLOY_DIR/" 2>/dev/null || {
    # If no dist directory, copy source files
    sudo cp -r ./* "$NEW_DEPLOY_DIR/"
    sudo rm -rf "$NEW_DEPLOY_DIR/.git" 2>/dev/null || true
    sudo rm -rf "$NEW_DEPLOY_DIR/node_modules" 2>/dev/null || true
}

# Install production dependencies
print_step "Installing production dependencies..."

sudo -u root bash -c "cd $NEW_DEPLOY_DIR && npm ci --only=production"

print_status "Production dependencies installed"

# Create systemd service files
print_step "Creating systemd service files..."

# API Gateway service
sudo tee /etc/systemd/system/portfolio-api-gateway.service > /dev/null << EOF
[Unit]
Description=Portfolio Tracker API Gateway
After=network.target

[Service]
Type=simple
User=portfolio
Group=portfolio
WorkingDirectory=$NEW_DEPLOY_DIR/packages/api-gateway
Environment=NODE_ENV=$ENVIRONMENT
EnvironmentFile=$ENV_FILE
ExecStart=/usr/bin/node src/secure-server.js
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
SyslogIdentifier=portfolio-api-gateway

# Security settings
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=$LOG_DIR

[Install]
WantedBy=multi-user.target
EOF

# User service
sudo tee /etc/systemd/system/portfolio-user-service.service > /dev/null << EOF
[Unit]
Description=Portfolio Tracker User Service
After=network.target

[Service]
Type=simple
User=portfolio
Group=portfolio
WorkingDirectory=$NEW_DEPLOY_DIR/packages/user-service
Environment=NODE_ENV=$ENVIRONMENT
EnvironmentFile=$ENV_FILE
ExecStart=/usr/bin/node src/secure-index.js
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
SyslogIdentifier=portfolio-user-service

# Security settings
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=$LOG_DIR

[Install]
WantedBy=multi-user.target
EOF

print_status "Systemd service files created"

# Create portfolio user if it doesn't exist
if ! id "portfolio" &>/dev/null; then
    print_step "Creating portfolio user..."
    sudo useradd -r -s /bin/false -d "$DEPLOY_DIR" portfolio
    print_status "Portfolio user created"
fi

# Set ownership
sudo chown -R portfolio:portfolio "$NEW_DEPLOY_DIR"
sudo chown -R portfolio:portfolio "$LOG_DIR"

# Update current symlink
print_step "Updating current deployment symlink..."

sudo rm -f "$DEPLOY_DIR/current"
sudo ln -sf "$NEW_DEPLOY_DIR" "$DEPLOY_DIR/current"

print_status "Deployment symlink updated"

# Reload systemd and start services
print_step "Starting services..."

sudo systemctl daemon-reload

# Enable and start services
services=("portfolio-api-gateway" "portfolio-user-service")

for service in "${services[@]}"; do
    sudo systemctl enable "$service"
    sudo systemctl restart "$service"
    
    # Wait for service to start
    sleep 5
    
    if sudo systemctl is-active --quiet "$service"; then
        print_status "$service started successfully"
    else
        print_error "$service failed to start"
        sudo systemctl status "$service"
        exit 1
    fi
done

# Setup log rotation
print_step "Setting up log rotation..."

sudo tee /etc/logrotate.d/portfolio-tracker > /dev/null << EOF
$LOG_DIR/*.log {
    daily
    missingok
    rotate 30
    compress
    delaycompress
    notifempty
    create 644 portfolio portfolio
    postrotate
        systemctl reload portfolio-api-gateway portfolio-user-service
    endscript
}
EOF

print_status "Log rotation configured"

# Setup monitoring
print_step "Setting up monitoring..."

# Create monitoring script
sudo tee "$DEPLOY_DIR/scripts/health-check.sh" > /dev/null << 'EOF'
#!/bin/bash

SERVICES=("portfolio-api-gateway" "portfolio-user-service")
HEALTH_ENDPOINTS=("https://localhost/health" "https://localhost:3001/health")

echo "Portfolio Tracker Health Check - $(date)"
echo "========================================"

# Check systemd services
for service in "${SERVICES[@]}"; do
    if systemctl is-active --quiet "$service"; then
        echo "✅ $service: Running"
    else
        echo "❌ $service: Not running"
    fi
done

# Check HTTP endpoints
for endpoint in "${HEALTH_ENDPOINTS[@]}"; do
    if curl -k -s "$endpoint" > /dev/null; then
        echo "✅ $endpoint: Responding"
    else
        echo "❌ $endpoint: Not responding"
    fi
done

# Check disk space
DISK_USAGE=$(df -h / | awk 'NR==2 {print $5}' | sed 's/%//')
if [ "$DISK_USAGE" -gt 80 ]; then
    echo "⚠️  Disk usage: ${DISK_USAGE}% (Warning: >80%)"
else
    echo "✅ Disk usage: ${DISK_USAGE}%"
fi

# Check memory usage
MEMORY_USAGE=$(free | awk 'NR==2{printf "%.0f", $3*100/$2}')
if [ "$MEMORY_USAGE" -gt 80 ]; then
    echo "⚠️  Memory usage: ${MEMORY_USAGE}% (Warning: >80%)"
else
    echo "✅ Memory usage: ${MEMORY_USAGE}%"
fi
EOF

sudo chmod +x "$DEPLOY_DIR/scripts/health-check.sh"

# Setup cron job for health checks
(sudo crontab -l 2>/dev/null; echo "*/5 * * * * $DEPLOY_DIR/scripts/health-check.sh >> $LOG_DIR/health-check.log 2>&1") | sudo crontab -

print_status "Health monitoring configured"

# Setup SSL certificate renewal (if using Let's Encrypt)
if [ "$ENVIRONMENT" = "production" ] && [ "$DOMAIN" != "localhost" ]; then
    print_step "Setting up SSL certificate auto-renewal..."
    
    # Add certbot renewal to cron
    (sudo crontab -l 2>/dev/null; echo "0 12 * * * /usr/bin/certbot renew --quiet --post-hook 'systemctl reload portfolio-api-gateway'") | sudo crontab -
    
    print_status "SSL certificate auto-renewal configured"
fi

# Run final security check
print_step "Running final security verification..."

sleep 10  # Wait for services to fully start

# Check if services are responding
API_GATEWAY_URL="https://localhost"
if curl -k -s "$API_GATEWAY_URL/health" > /dev/null; then
    print_status "API Gateway is responding"
else
    print_warning "API Gateway is not responding at $API_GATEWAY_URL"
fi

# Run security audit on deployed application
if [ -f "./scripts/security-audit.sh" ]; then
    API_BASE_URL="$API_GATEWAY_URL" ./scripts/security-audit.sh || {
        print_warning "Security audit found issues in deployed application"
    }
fi

# Cleanup old releases (keep last 5)
print_step "Cleaning up old releases..."

sudo find "$DEPLOY_DIR/releases" -maxdepth 1 -type d -name "20*" | sort -r | tail -n +6 | sudo xargs rm -rf

print_status "Old releases cleaned up"

# Final deployment summary
print_step "Deployment Summary"
echo "=================="
echo "Environment: $ENVIRONMENT"
echo "Domain: $DOMAIN"
echo "Deployment Directory: $NEW_DEPLOY_DIR"
echo "Current Symlink: $DEPLOY_DIR/current"
echo "SSL Certificates: $DEPLOY_DIR/certs/"
echo "Configuration: $ENV_FILE"
echo "Logs: $LOG_DIR"
echo ""
echo "Services:"
for service in "${services[@]}"; do
    if sudo systemctl is-active --quiet "$service"; then
        echo "  ✅ $service: Running"
    else
        echo "  ❌ $service: Not running"
    fi
done
echo ""
echo "URLs:"
echo "  API Gateway: https://$DOMAIN"
echo "  Health Check: https://$DOMAIN/health"
echo "  Security Metrics: https://$DOMAIN/security/metrics"
echo ""
echo "Next Steps:"
echo "1. Review and update configuration in $ENV_FILE"
echo "2. Configure your DNS to point to this server"
echo "3. Set up external monitoring and alerting"
echo "4. Review security logs in $LOG_DIR"
echo "5. Test all application functionality"

print_status "🎉 Secure deployment completed successfully!"

# Set exit code based on service status
for service in "${services[@]}"; do
    if ! sudo systemctl is-active --quiet "$service"; then
        print_error "Some services are not running. Check logs for details."
        exit 1
    fi
done

exit 0