#!/bin/bash

# Traefik Production Deployment Script
# Comprehensive deployment with security, monitoring, and validation

set -euo pipefail

# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
DOMAIN="${DOMAIN:-localhost}"
EMAIL="${EMAIL:-admin@localhost}"

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

# Logging
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"
}

# Validation functions
check_prerequisites() {
    log_info "Checking prerequisites..."
    
    # Check if running as root
    if [[ $EUID -eq 0 ]]; then
        log_error "This script should not be run as root for security reasons"
        exit 1
    fi
    
    # Check Docker
    if ! command -v docker &> /dev/null; then
        log_error "Docker is not installed"
        exit 1
    fi
    
    # Check Docker Swarm
    if ! docker info --format '{{.Swarm.LocalNodeState}}' | grep -q "active"; then
        log_error "Docker Swarm is not initialized"
        log_info "Initialize with: docker swarm init"
        exit 1
    fi
    
    # Check SELinux
    if command -v getenforce &> /dev/null; then
        SELINUX_STATUS=$(getenforce)
        if [[ "$SELINUX_STATUS" != "Enforcing" && "$SELINUX_STATUS" != "Permissive" ]]; then
            log_error "SELinux is disabled. Enable SELinux for production security."
            exit 1
        fi
        log_info "SELinux status: $SELINUX_STATUS"
    fi
    
    # Check required ports
    for port in 80 443 8080; do
        if netstat -tlnp | grep -q ":$port "; then
            log_warning "Port $port is already in use"
        fi
    done
    
    log_success "Prerequisites check completed"
}

install_selinux_policy() {
    log_info "Installing SELinux policy for Traefik Docker access..."
    
    if [[ ! -f "$PROJECT_ROOT/selinux/install_selinux_policy.sh" ]]; then
        log_error "SELinux policy installation script not found"
        exit 1
    fi
    
    cd "$PROJECT_ROOT/selinux"
    chmod +x install_selinux_policy.sh
    
    if ./install_selinux_policy.sh; then
        log_success "SELinux policy installed successfully"
    else
        log_error "Failed to install SELinux policy"
        exit 1
    fi
}

create_directories() {
    log_info "Creating required directories..."
    
    # Traefik directories
    sudo mkdir -p /opt/traefik/{letsencrypt,logs}
    
    # Monitoring directories
    sudo mkdir -p /opt/monitoring/{prometheus/{data,config},grafana/{data,config}}
    sudo mkdir -p /opt/monitoring/{alertmanager/{data,config},loki/data,promtail/config}
    
    # Set permissions
    sudo chown -R $(id -u):$(id -g) /opt/traefik
    sudo chown -R 65534:65534 /opt/monitoring/prometheus
    sudo chown -R 472:472 /opt/monitoring/grafana
    sudo chown -R 65534:65534 /opt/monitoring/alertmanager
    sudo chown -R 10001:10001 /opt/monitoring/loki
    
    log_success "Directories created with proper permissions"
}

setup_network() {
    log_info "Setting up Docker overlay network..."
    
    if docker network ls | grep -q "traefik-public"; then
        log_warning "Network traefik-public already exists"
    else
        docker network create \
            --driver overlay \
            --attachable \
            --subnet 10.0.1.0/24 \
            traefik-public
        log_success "Created traefik-public overlay network"
    fi
}

deploy_configurations() {
    log_info "Deploying monitoring configurations..."
    
    # Copy monitoring configs
    sudo cp "$PROJECT_ROOT/configs/monitoring/prometheus.yml" /opt/monitoring/prometheus/config/
    sudo cp "$PROJECT_ROOT/configs/monitoring/traefik_rules.yml" /opt/monitoring/prometheus/config/
    sudo cp "$PROJECT_ROOT/configs/monitoring/alertmanager.yml" /opt/monitoring/alertmanager/config/
    
    # Create environment file
    cat > /tmp/traefik.env << EOF
DOMAIN=$DOMAIN
EMAIL=$EMAIL
EOF
    sudo mv /tmp/traefik.env /opt/traefik/.env
    
    log_success "Configuration files deployed"
}

deploy_traefik() {
    log_info "Deploying Traefik stack..."
    
    export DOMAIN EMAIL
    
    if docker stack deploy -c "$PROJECT_ROOT/stacks/core/traefik-production.yml" traefik; then
        log_success "Traefik stack deployed successfully"
    else
        log_error "Failed to deploy Traefik stack"
        exit 1
    fi
}

deploy_monitoring() {
    log_info "Deploying monitoring stack..."
    
    export DOMAIN
    
    if docker stack deploy -c "$PROJECT_ROOT/stacks/monitoring/traefik-monitoring.yml" monitoring; then
        log_success "Monitoring stack deployed successfully"
    else
        log_error "Failed to deploy monitoring stack"
        exit 1
    fi
}

wait_for_services() {
    log_info "Waiting for services to become healthy..."
    
    local max_attempts=30
    local attempt=0
    
    while [[ $attempt -lt $max_attempts ]]; do
        local healthy_count=0
        
        # Check Traefik
        if curl -sf http://localhost:8080/ping >/dev/null 2>&1; then
            ((healthy_count++))
        fi
        
        # Check Prometheus
        if curl -sf http://localhost:9090/-/healthy >/dev/null 2>&1; then
            ((healthy_count++))
        fi
        
        if [[ $healthy_count -eq 2 ]]; then
            log_success "All services are healthy"
            return 0
        fi
        
        log_info "Attempt $((attempt + 1))/$max_attempts - $healthy_count/2 services healthy"
        sleep 10
        ((attempt++))
    done
    
    log_warning "Some services may not be healthy yet"
}

validate_deployment() {
    log_info "Validating deployment..."
    
    local validation_passed=true
    
    # Test Traefik API
    if curl -sf http://localhost:8080/api/overview >/dev/null; then
        log_success "✓ Traefik API accessible"
    else
        log_error "✗ Traefik API not accessible"
        validation_passed=false
    fi
    
    # Test authentication (should fail without credentials)
    if curl -sf "http://localhost:8080/dashboard/" >/dev/null; then
        log_error "✗ Dashboard accessible without authentication"
        validation_passed=false
    else
        log_success "✓ Dashboard requires authentication"
    fi
    
    # Test authentication with credentials
    if curl -sf -u "admin:secure_password_2024" "http://localhost:8080/dashboard/" >/dev/null; then
        log_success "✓ Dashboard accessible with correct credentials"
    else
        log_error "✗ Dashboard not accessible with credentials"
        validation_passed=false
    fi
    
    # Test HTTPS redirect
    local redirect_response=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost/")
    if [[ "$redirect_response" == "301" || "$redirect_response" == "302" ]]; then
        log_success "✓ HTTP to HTTPS redirect working"
    else
        log_warning "⚠ HTTP redirect response: $redirect_response"
    fi
    
    # Test Prometheus metrics
    if curl -sf http://localhost:8080/metrics | grep -q "traefik_"; then
        log_success "✓ Prometheus metrics available"
    else
        log_error "✗ Prometheus metrics not available"
        validation_passed=false
    fi
    
    # Check Docker socket access
    if docker service logs traefik_traefik --tail 10 | grep -q "permission denied"; then
        log_error "✗ Docker socket permission issues detected"
        validation_passed=false
    else
        log_success "✓ Docker socket access working"
    fi
    
    if [[ "$validation_passed" == true ]]; then
        log_success "All validation checks passed"
        return 0
    else
        log_error "Some validation checks failed"
        return 1
    fi
}

generate_summary() {
    log_info "Generating deployment summary..."
    
    cat << EOF

🎉 Traefik Production Deployment Complete!

📊 Services Deployed:
  • Traefik v3.1 (Load Balancer & Reverse Proxy)
  • Prometheus (Metrics & Alerting)
  • Grafana (Monitoring Dashboards)
  • AlertManager (Alert Management)
  • Loki + Promtail (Log Aggregation)

🔐 Access Points:
  • Traefik Dashboard: https://traefik.$DOMAIN/dashboard/
  • Prometheus: https://prometheus.$DOMAIN
  • Grafana: https://grafana.$DOMAIN
  • AlertManager: https://alertmanager.$DOMAIN

🔑 Default Credentials:
  • Username: admin
  • Password: secure_password_2024
  • ⚠️  CHANGE THESE IN PRODUCTION!

🛡️ Security Features:
  • ✅ SELinux policy installed
  • ✅ TLS/SSL with automatic certificates
  • ✅ Security headers enabled
  • ✅ Rate limiting configured
  • ✅ Authentication required
  • ✅ Monitoring & alerting active

📝 Next Steps:
  1. Update DNS records to point to this server
  2. Change default passwords
  3. Configure alert notifications
  4. Review security checklist: TRAEFIK_SECURITY_CHECKLIST.md
  5. Set up regular backups

📚 Documentation:
  • Full Guide: TRAEFIK_DEPLOYMENT_GUIDE.md
  • Security Checklist: TRAEFIK_SECURITY_CHECKLIST.md

EOF
}

# Main deployment function
main() {
    log_info "Starting Traefik Production Deployment"
    log_info "Domain: $DOMAIN"
    log_info "Email: $EMAIL"
    
    check_prerequisites
    install_selinux_policy
    create_directories
    setup_network
    deploy_configurations
    deploy_traefik
    deploy_monitoring
    wait_for_services
    
    if validate_deployment; then
        generate_summary
        log_success "🎉 Deployment completed successfully!"
    else
        log_error "❌ Deployment validation failed. Check logs for details."
        exit 1
    fi
}

# Run main function
main "$@"