#!/bin/bash

# SSL Certificate Initialization Script for CuliUptime Production
# This script initializes SSL certificates using Let's Encrypt with HTTP-01 validation

set -e

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

# Configuration
COMPOSE_FILE="docker-compose.prd.yml"
NGINX_CONF_TEMPLATE="infra/nginx/conf.d/culiuptime.conf"

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

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

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

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

# Function to check if domain is provided
check_domain() {
    # Try to read from .env file if DOMAIN not provided
    if [ -z "$DOMAIN" ] && [ -f ".env" ]; then
        DOMAIN=$(grep "^DOMAIN=" .env | head -1 | cut -d'=' -f2)
        if [ -n "$DOMAIN" ]; then
            print_status "Using domain from .env file: $DOMAIN"
        fi
    fi

    if [ -z "$DOMAIN" ]; then
        print_error "Domain not provided!"
        echo "Usage: DOMAIN=yourdomain.com EMAIL=your@email.com $0"
        echo "Example: DOMAIN=monitoring.example.com EMAIL=admin@example.com $0"
        echo "Or set DOMAIN=yourdomain.com in your .env file"
        exit 1
    fi
}

# Function to check if email is provided
check_email() {
    if [ -z "$EMAIL" ]; then
        print_error "Email not provided!"
        echo "Usage: DOMAIN=yourdomain.com EMAIL=your@email.com $0"
        echo "Example: DOMAIN=culiuptime.example.com EMAIL=admin@example.com $0"
        exit 1
    fi
}

# Function to validate domain format
validate_domain() {
    if [[ ! "$DOMAIN" =~ ^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$ ]]; then
        print_error "Invalid domain format: $DOMAIN"
        exit 1
    fi
}

# Function to validate email format
validate_email() {
    if [[ ! "$EMAIL" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
        print_error "Invalid email format: $EMAIL"
        exit 1
    fi
}

# Function to check if certificates already exist
check_existing_certificates() {
    if docker-compose -f $COMPOSE_FILE exec nginx test -f /etc/letsencrypt/live/$DOMAIN/fullchain.pem 2>/dev/null; then
        print_warning "SSL certificates for $DOMAIN already exist!"
        read -p "Do you want to continue and potentially overwrite them? (y/N): " -n 1 -r
        echo
        if [[ ! $REPLY =~ ^[Yy]$ ]]; then
            print_status "Exiting without changes."
            exit 0
        fi
    fi
}

# Function to update nginx configuration with the actual domain
update_nginx_config() {
    print_status "Updating nginx configuration for domain: $DOMAIN"

    # Replace placeholder with actual domain
    sed "s/DOMAIN_PLACEHOLDER/$DOMAIN/g" $NGINX_CONF_TEMPLATE > ${NGINX_CONF_TEMPLATE}.tmp
    mv ${NGINX_CONF_TEMPLATE}.tmp $NGINX_CONF_TEMPLATE

    print_success "Nginx configuration updated successfully!"
}

# Function to build frontend
build_frontend() {
    print_status "Building React frontend for production..."

    if ! docker-compose -f $COMPOSE_FILE --profile build run --rm frontend_build; then
        print_error "Failed to build frontend!"
        exit 1
    fi

    print_success "Frontend built successfully!"
}

# Function to start services without SSL
start_services_http() {
    print_status "Starting services in HTTP mode for certificate generation..."

    # Create a temporary nginx config for HTTP-only
    cat > infra/nginx/conf.d/culiuptime-temp.conf << EOF
server {
    listen 80;
    server_name $DOMAIN;
    server_tokens off;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
        try_files \$uri =404;
    }

    location / {
        root /usr/share/nginx/html;
        index index.html index.htm;
        try_files \$uri \$uri/ /index.html;
    }
}
EOF

    # Rename main config temporarily
    mv infra/nginx/conf.d/culiuptime.conf infra/nginx/conf.d/culiuptime.conf.ssl

    # Start services
    docker-compose -f $COMPOSE_FILE up -d nginx postgres redis backend celery_worker celery_beat

    # Wait for nginx to be ready
    print_status "Waiting for nginx to be ready..."
    sleep 10
}

# Function to generate SSL certificates
generate_certificates() {
    print_status "Generating SSL certificates for domain: $DOMAIN"
    print_status "Email: $EMAIL"

    # Generate certificates using HTTP-01 challenge
    if docker-compose -f $COMPOSE_FILE run --rm certbot \
        certonly \
        --webroot \
        --webroot-path=/var/www/certbot \
        --email $EMAIL \
        --agree-tos \
        --no-eff-email \
        --force-renewal \
        -d $DOMAIN; then

        print_success "SSL certificates generated successfully!"
    else
        print_error "Failed to generate SSL certificates!"
        cleanup_temp_config
        exit 1
    fi
}

# Function to cleanup temporary configuration
cleanup_temp_config() {
    print_status "Restoring SSL nginx configuration..."

    # Remove temporary config
    rm -f infra/nginx/conf.d/culiuptime-temp.conf

    # Restore SSL config
    mv infra/nginx/conf.d/culiuptime.conf.ssl infra/nginx/conf.d/culiuptime.conf
}

# Function to restart nginx with SSL
restart_nginx_ssl() {
    print_status "Restarting nginx with SSL configuration..."

    cleanup_temp_config

    # Reload nginx configuration
    if docker-compose -f $COMPOSE_FILE exec nginx nginx -s reload; then
        print_success "Nginx restarted with SSL configuration!"
    else
        print_error "Failed to restart nginx with SSL!"
        exit 1
    fi
}

# Function to verify SSL setup
verify_ssl() {
    print_status "Verifying SSL certificate setup..."

    # Wait a moment for nginx to fully reload
    sleep 5

    # Test SSL certificate
    if timeout 10 openssl s_client -connect $DOMAIN:443 -servername $DOMAIN </dev/null 2>/dev/null | grep -q "BEGIN CERTIFICATE"; then
        print_success "SSL certificate is working correctly!"
    else
        print_warning "SSL certificate verification failed. Please check manually."
    fi

    print_status "You can verify SSL setup by visiting: https://$DOMAIN"
}

# Function to show post-setup information
show_post_setup_info() {
    echo ""
    print_success "===== SSL Setup Complete ====="
    echo ""
    echo "Domain: $DOMAIN"
    echo "Certificate Location: /etc/letsencrypt/live/$DOMAIN/"
    echo "Certificate Auto-Renewal: Enabled (daily check at 2 AM)"
    echo ""
    print_status "Next Steps:"
    echo "1. Verify your application is accessible at: https://$DOMAIN"
    echo "2. Check SSL rating at: https://www.ssllabs.com/ssltest/analyze.html?d=$DOMAIN"
    echo "3. Monitor certificate expiration and renewal in container logs"
    echo ""
    print_status "Useful Commands:"
    echo "- View logs: docker-compose -f $COMPOSE_FILE logs -f"
    echo "- Check certificate: docker-compose -f $COMPOSE_FILE exec nginx openssl x509 -in /etc/letsencrypt/live/$DOMAIN/fullchain.pem -text -noout"
    echo "- Manual renewal: docker-compose -f $COMPOSE_FILE exec certbot certbot renew"
    echo ""
}

# Main execution
main() {
    print_status "=== CuliUptime SSL Certificate Setup ==="

    # Validate inputs
    check_domain
    check_email
    validate_domain
    validate_email

    print_status "Domain: $DOMAIN"
    print_status "Email: $EMAIL"

    # Confirm before proceeding
    read -p "Continue with SSL setup? (y/N): " -n 1 -r
    echo
    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
        print_status "Setup cancelled."
        exit 0
    fi

    # Check for existing certificates
    check_existing_certificates

    # Update nginx configuration
    update_nginx_config

    # Build frontend
    build_frontend

    # Start services in HTTP mode
    start_services_http

    # Generate certificates
    generate_certificates

    # Restart nginx with SSL
    restart_nginx_ssl

    # Verify SSL setup
    verify_ssl

    # Show post-setup information
    show_post_setup_info
}

# Execute main function
main
