#!/bin/bash

# Standard Architecture Deployment Script
# Automatically deploys applications with Nginx + Unix Socket + Cloudflare Tunnel

set -euo pipefail

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

# Default values
APP_NAME=""
DOMAIN=""
PORT="8080"
TYPE="webapp"
ENVIRONMENT="production"
SKIP_TUNNEL=false
SKIP_SYSTEMD=false
DRY_RUN=false

# Directories
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TEMPLATE_DIR="$(dirname "$SCRIPT_DIR")/templates"
PROJECT_DIR=""

# Usage function
usage() {
    cat << EOF
Standard Architecture Deployment Script

USAGE:
    $0 --app=APP_NAME --domain=DOMAIN [OPTIONS]

REQUIRED:
    --app=NAME          Application name (lowercase, alphanumeric + hyphens)
    --domain=DOMAIN     Primary domain for the application

OPTIONS:
    --port=PORT         Internal port (default: 8080)
    --type=TYPE         Application type: webapp, api, database (default: webapp)
    --env=ENVIRONMENT   Environment: development, staging, production (default: production)
    --project-dir=PATH  Project directory (default: ./APP_NAME)
    --skip-tunnel       Skip Cloudflare Tunnel setup
    --skip-systemd      Skip systemd service creation
    --dry-run           Show what would be done without executing
    --help             Show this help message

EXAMPLES:
    # Basic web application
    $0 --app=myapp --domain=myapp.com

    # API service
    $0 --app=api --domain=api.myapp.com --type=api --port=8080

    # Development environment
    $0 --app=myapp-dev --domain=dev.myapp.com --env=development

    # With custom project directory
    $0 --app=myapp --domain=myapp.com --project-dir=/opt/myapp
EOF
}

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

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

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

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

# Parse command line arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        --app=*)
            APP_NAME="${1#*=}"
            shift
            ;;
        --domain=*)
            DOMAIN="${1#*=}"
            shift
            ;;
        --port=*)
            PORT="${1#*=}"
            shift
            ;;
        --type=*)
            TYPE="${1#*=}"
            shift
            ;;
        --env=*)
            ENVIRONMENT="${1#*=}"
            shift
            ;;
        --project-dir=*)
            PROJECT_DIR="${1#*=}"
            shift
            ;;
        --skip-tunnel)
            SKIP_TUNNEL=true
            shift
            ;;
        --skip-systemd)
            SKIP_SYSTEMD=true
            shift
            ;;
        --dry-run)
            DRY_RUN=true
            shift
            ;;
        --help)
            usage
            exit 0
            ;;
        *)
            log_error "Unknown option: $1"
            usage
            exit 1
            ;;
    esac
done

# Validate required parameters
if [[ -z "$APP_NAME" ]]; then
    log_error "Application name is required (--app=NAME)"
    usage
    exit 1
fi

if [[ -z "$DOMAIN" ]]; then
    log_error "Domain is required (--domain=DOMAIN)"
    usage
    exit 1
fi

# Validate app name format
if ! [[ "$APP_NAME" =~ ^[a-z0-9-]+$ ]]; then
    log_error "App name must contain only lowercase letters, numbers, and hyphens"
    exit 1
fi

# Set default project directory
if [[ -z "$PROJECT_DIR" ]]; then
    PROJECT_DIR="$(pwd)/$APP_NAME"
fi

# Validate type
case $TYPE in
    webapp|api|database)
        ;;
    *)
        log_error "Invalid type: $TYPE. Must be webapp, api, or database"
        exit 1
        ;;
esac

# Check dependencies
check_dependencies() {
    log_info "Checking dependencies..."
    
    local deps=("docker" "nginx" "envsubst")
    local missing=()
    
    for dep in "${deps[@]}"; do
        if ! command -v "$dep" >/dev/null 2>&1; then
            missing+=("$dep")
        fi
    done
    
    if ! $SKIP_TUNNEL && ! command -v "cloudflared" >/dev/null 2>&1; then
        missing+=("cloudflared")
    fi
    
    if [[ ${#missing[@]} -ne 0 ]]; then
        log_error "Missing dependencies: ${missing[*]}"
        log_error "Please install missing packages and try again"
        exit 1
    fi
    
    log_success "All dependencies found"
}

# Create project structure
create_project_structure() {
    log_info "Creating project structure at $PROJECT_DIR..."
    
    if $DRY_RUN; then
        log_info "[DRY RUN] Would create directory structure"
        return
    fi
    
    mkdir -p "$PROJECT_DIR"/{nginx,cloudflared,systemd,scripts,logs}
    mkdir -p "/var/run/$APP_NAME"
    
    # Set proper permissions
    sudo chown "${USER}:www-data" "/var/run/$APP_NAME"
    chmod 775 "/var/run/$APP_NAME"
    
    log_success "Project structure created"
}

# Generate configuration files
generate_configs() {
    log_info "Generating configuration files..."
    
    # Set template variables
    export APP_NAME="$APP_NAME"
    export DOMAIN="$DOMAIN"
    export CF_TUNNEL_PORT="$PORT"
    export PRIMARY_DOMAIN="$DOMAIN"
    export API_DOMAIN="api.$DOMAIN"
    export ADMIN_DOMAIN="admin.$DOMAIN" 
    export INTERNAL_PORT="$PORT"
    export NGINX_PORT="$PORT"
    export MEMORY_LIMIT="512M"
    export CPU_LIMIT="0.5"
    export LOG_LEVEL="info"
    export MAX_UPLOAD_SIZE="10M"
    export DB_NAME="$APP_NAME"
    export DB_USER="$APP_NAME"
    export DB_PASSWORD="$(openssl rand -base64 32)"
    export USER="$(whoami)"
    export TUNNEL_ID="" # Will be set if tunnel is created
    
    if $DRY_RUN; then
        log_info "[DRY RUN] Would generate configuration files"
        return
    fi
    
    # Generate Docker Compose
    envsubst < "$TEMPLATE_DIR/docker-compose.yml.template" > "$PROJECT_DIR/docker-compose.yml"
    log_success "Generated docker-compose.yml"
    
    # Generate Nginx config
    envsubst < "$TEMPLATE_DIR/nginx.conf.template" > "$PROJECT_DIR/nginx/${APP_NAME}.conf"
    log_success "Generated nginx configuration"
    
    # Generate Cloudflare Tunnel config
    if ! $SKIP_TUNNEL; then
        envsubst < "$TEMPLATE_DIR/cloudflared.yml.template" > "$PROJECT_DIR/cloudflared/config.yml"
        log_success "Generated Cloudflare Tunnel configuration"
    fi
    
    # Create .env file
    cat > "$PROJECT_DIR/.env" << EOF
# Application Configuration
APP_NAME=$APP_NAME
DOMAIN=$DOMAIN
PORT=$PORT
ENVIRONMENT=$ENVIRONMENT

# Database Configuration
DB_NAME=$DB_NAME
DB_USER=$DB_USER
DB_PASSWORD=$DB_PASSWORD

# Socket Configuration
SOCKET_PATH=/var/run/$APP_NAME/$APP_NAME.sock

# Security
JWT_SECRET=$(openssl rand -base64 64)
ENCRYPTION_KEY=$(openssl rand -base64 32)
EOF
    
    chmod 600 "$PROJECT_DIR/.env"
    log_success "Generated .env file"
}

# Setup Nginx
setup_nginx() {
    log_info "Setting up Nginx..."
    
    if $DRY_RUN; then
        log_info "[DRY RUN] Would configure Nginx"
        return
    fi
    
    # Create symlink to sites-enabled
    sudo ln -sf "$PROJECT_DIR/nginx/${APP_NAME}.conf" "/etc/nginx/sites-enabled/${APP_NAME}"
    
    # Test configuration
    if sudo nginx -t; then
        sudo systemctl reload nginx
        log_success "Nginx configured and reloaded"
    else
        log_error "Nginx configuration test failed"
        exit 1
    fi
}

# Setup Cloudflare Tunnel
setup_tunnel() {
    if $SKIP_TUNNEL; then
        log_info "Skipping Cloudflare Tunnel setup"
        return
    fi
    
    log_info "Setting up Cloudflare Tunnel..."
    
    if $DRY_RUN; then
        log_info "[DRY RUN] Would setup Cloudflare Tunnel"
        return
    fi
    
    # Create tunnel
    local tunnel_output
    tunnel_output=$(cloudflared tunnel create "$APP_NAME" 2>/dev/null)
    TUNNEL_ID=$(echo "$tunnel_output" | grep -oE '[a-f0-9-]{36}')
    
    if [[ -z "$TUNNEL_ID" ]]; then
        log_error "Failed to create Cloudflare Tunnel"
        exit 1
    fi
    
    log_success "Created tunnel: $TUNNEL_ID"
    
    # Update config with tunnel ID
    sed -i "s/{{TUNNEL_ID}}/$TUNNEL_ID/g" "$PROJECT_DIR/cloudflared/config.yml"
    
    # Route DNS
    cloudflared tunnel route dns "$TUNNEL_ID" "$DOMAIN"
    cloudflared tunnel route dns "$TUNNEL_ID" "api.$DOMAIN"
    
    log_success "DNS routes configured"
    
    # Create systemd service
    if ! $SKIP_SYSTEMD; then
        cat > "$PROJECT_DIR/systemd/${APP_NAME}-tunnel.service" << EOF
[Unit]
Description=Cloudflare Tunnel for $APP_NAME
After=network.target
Requires=network.target

[Service]
Type=simple
User=$(whoami)
WorkingDirectory=$PROJECT_DIR/cloudflared
ExecStart=cloudflared tunnel --config $PROJECT_DIR/cloudflared/config.yml run
Restart=always
RestartSec=5
KillMode=mixed
KillSignal=SIGINT
TimeoutStopSec=30

[Install]
WantedBy=multi-user.target
EOF
        
        sudo ln -sf "$PROJECT_DIR/systemd/${APP_NAME}-tunnel.service" "/etc/systemd/system/${APP_NAME}-tunnel.service"
        sudo systemctl daemon-reload
        sudo systemctl enable "${APP_NAME}-tunnel.service"
        
        log_success "Tunnel systemd service created"
    fi
}

# Create deployment script
create_deployment_script() {
    log_info "Creating deployment script..."
    
    if $DRY_RUN; then
        log_info "[DRY RUN] Would create deployment script"
        return
    fi
    
    cat > "$PROJECT_DIR/scripts/start.sh" << 'EOF'
#!/bin/bash
set -e

APP_NAME="{{APP_NAME}}"
PROJECT_DIR="{{PROJECT_DIR}}"

echo "Starting $APP_NAME..."

# Ensure socket directory exists
sudo mkdir -p "/var/run/$APP_NAME"
sudo chown "$(whoami):www-data" "/var/run/$APP_NAME"
chmod 775 "/var/run/$APP_NAME"

# Start Docker containers
cd "$PROJECT_DIR"
docker-compose up -d

# Wait for services to be ready
echo "Waiting for services to start..."
sleep 10

# Health check
if curl --unix-socket "/var/run/$APP_NAME/$APP_NAME.sock" http://localhost/health >/dev/null 2>&1; then
    echo "✅ Application is healthy"
else
    echo "⚠️  Health check failed, check logs:"
    docker-compose logs --tail=20
fi

# Start tunnel (if configured)
if systemctl is-enabled "${APP_NAME}-tunnel.service" >/dev/null 2>&1; then
    sudo systemctl start "${APP_NAME}-tunnel.service"
    echo "✅ Tunnel started"
fi

echo "🚀 Deployment complete!"
echo "📊 Monitor with: docker-compose logs -f"
echo "🌐 Access at: https://{{DOMAIN}}"
EOF
    
    # Replace template variables
    sed -i "s/{{APP_NAME}}/$APP_NAME/g" "$PROJECT_DIR/scripts/start.sh"
    sed -i "s|{{PROJECT_DIR}}|$PROJECT_DIR|g" "$PROJECT_DIR/scripts/start.sh"
    sed -i "s/{{DOMAIN}}/$DOMAIN/g" "$PROJECT_DIR/scripts/start.sh"
    
    chmod +x "$PROJECT_DIR/scripts/start.sh"
    log_success "Deployment script created"
}

# Main deployment
main() {
    log_info "🚀 Starting Standard Architecture deployment"
    log_info "App: $APP_NAME"
    log_info "Domain: $DOMAIN"
    log_info "Type: $TYPE"
    log_info "Environment: $ENVIRONMENT"
    log_info "Project Dir: $PROJECT_DIR"
    
    if $DRY_RUN; then
        log_warning "DRY RUN MODE - No changes will be made"
    fi
    
    check_dependencies
    create_project_structure
    generate_configs
    setup_nginx
    setup_tunnel
    create_deployment_script
    
    log_success "🎉 Deployment setup complete!"
    
    if ! $DRY_RUN; then
        echo ""
        log_info "Next steps:"
        echo "1. Add your application code to: $PROJECT_DIR"
        echo "2. Update Dockerfile to bind to unix socket: /var/run/$APP_NAME/$APP_NAME.sock"
        echo "3. Build and start: cd $PROJECT_DIR && bash scripts/start.sh"
        echo "4. Monitor logs: docker-compose logs -f"
        echo "5. Test: curl https://$DOMAIN/health"
    fi
}

# Run main function
main "$@"