#!/bin/bash
# Deploy Traefik Reverse Proxy
# This script deploys Traefik with SSL, security, and monitoring

set -euo pipefail

echo "🌐 Deploying Traefik reverse proxy..."

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

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

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

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

# Configuration
MANAGER_HOST="omv800"
TRAEFIK_CONFIG_DIR="/opt/migration/configs/traefik"
DOMAIN="yourdomain.com"
EMAIL="admin@yourdomain.com"

# 1. Create Traefik configuration directory
print_status "Step 1: Creating Traefik configuration directory..."
mkdir -p "$TRAEFIK_CONFIG_DIR"
mkdir -p "$TRAEFIK_CONFIG_DIR/dynamic"
mkdir -p "$TRAEFIK_CONFIG_DIR/certificates"

# 2. Create Traefik static configuration
print_status "Step 2: Creating Traefik static configuration..."
cat > "$TRAEFIK_CONFIG_DIR/traefik.yml" << EOF
# Traefik Static Configuration
global:
  checkNewVersion: false
  sendAnonymousUsage: false

api:
  dashboard: true
  insecure: false

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entrypoint:
          to: websecure
          scheme: https
          permanent: true
  
  websecure:
    address: ":443"
    http:
      tls:
        certResolver: letsencrypt
        domains:
          - main: "*.${DOMAIN}"
            sans:
              - "*.${DOMAIN}"

providers:
  docker:
    swarmMode: true
    exposedByDefault: false
    network: traefik-public
    watch: true
  
  file:
    directory: /etc/traefik/dynamic
    watch: true

certificatesResolvers:
  letsencrypt:
    acme:
      email: ${EMAIL}
      storage: /certificates/acme.json
      httpChallenge:
        entryPoint: web

log:
  level: INFO
  format: json

accessLog:
  filePath: /var/log/traefik/access.log
  format: json
  fields:
    defaultMode: keep
    headers:
      defaultMode: keep

metrics:
  prometheus:
    addEntryPointsLabels: true
    addServicesLabels: true
    buckets:
      - 0.1
      - 0.3
      - 1.2
      - 5.0

ping:
  entryPoint: web

providers:
  docker:
    swarmMode: true
    exposedByDefault: false
    network: traefik-public
    watch: true
  
  file:
    directory: /etc/traefik/dynamic
    watch: true
EOF

# 3. Create dynamic configuration
print_status "Step 3: Creating dynamic configuration..."

# Copy middleware configuration
cp "$(dirname "$0")/../configs/traefik/dynamic/middleware.yml" "$TRAEFIK_CONFIG_DIR/dynamic/"

# Create service-specific configurations
cat > "$TRAEFIK_CONFIG_DIR/dynamic/services.yml" << EOF
# Service-specific configurations
http:
  routers:
    # Immich Photo Management
    immich-api:
      rule: "Host(\`immich.${DOMAIN}\`) && PathPrefix(\`/api\`)"
      service: immich-api
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt
      middlewares:
        - security-headers@file
        - rate-limit@file
        - cors@file
    
    immich-web:
      rule: "Host(\`immich.${DOMAIN}\`)"
      service: immich-web
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt
      middlewares:
        - security-headers@file
        - rate-limit@file
        - compression@file
    
    # Jellyfin Media Server
    jellyfin:
      rule: "Host(\`jellyfin.${DOMAIN}\`)"
      service: jellyfin
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt
      middlewares:
        - security-headers@file
        - rate-limit@file
        - compression@file
    
    # Home Assistant
    homeassistant:
      rule: "Host(\`home.${DOMAIN}\`)"
      service: homeassistant
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt
      middlewares:
        - security-headers@file
        - rate-limit@file
        - websocket@file
    
    # AppFlowy Collaboration
    appflowy:
      rule: "Host(\`appflowy.${DOMAIN}\`)"
      service: appflowy
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt
      middlewares:
        - security-headers@file
        - rate-limit@file
        - cors@file
    
    # Paperless Document Management
    paperless:
      rule: "Host(\`paperless.${DOMAIN}\`)"
      service: paperless
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt
      middlewares:
        - security-headers@file
        - rate-limit@file
        - auth@file
    
    # Portainer Container Management
    portainer:
      rule: "Host(\`portainer.${DOMAIN}\`)"
      service: portainer
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt
      middlewares:
        - security-headers@file
        - auth@file
        - ip-whitelist@file
    
    # Grafana Monitoring
    grafana:
      rule: "Host(\`grafana.${DOMAIN}\`)"
      service: grafana
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt
      middlewares:
        - security-headers@file
        - auth@file
        - ip-whitelist@file
    
    # Prometheus Metrics
    prometheus:
      rule: "Host(\`prometheus.${DOMAIN}\`)"
      service: prometheus
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt
      middlewares:
        - security-headers@file
        - auth@file
        - ip-whitelist@file
    
    # Uptime Kuma Monitoring
    uptime-kuma:
      rule: "Host(\`uptime.${DOMAIN}\`)"
      service: uptime-kuma
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt
      middlewares:
        - security-headers@file
        - auth@file
        - ip-whitelist@file

  services:
    # Service definitions will be auto-discovered by Docker provider
    # These are fallback definitions for external services
    
    # Error service for maintenance pages
    error-service:
      loadBalancer:
        servers:
          - url: "http://error-page:8080"
    
    # Auth service for forward authentication
    auth-service:
      loadBalancer:
        servers:
          - url: "http://auth-service:8080"
EOF

# 4. Create users file for basic auth
print_status "Step 4: Creating users file for basic auth..."
cat > "$TRAEFIK_CONFIG_DIR/users" << EOF
# Basic Auth Users
# Format: username:hashed_password
# Generate with: htpasswd -nb username password
admin:\$2y\$10\$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi
migration:\$2y\$10\$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi
EOF

# 5. Set proper permissions
print_status "Step 5: Setting proper permissions..."
chmod 600 "$TRAEFIK_CONFIG_DIR/users"
chmod 644 "$TRAEFIK_CONFIG_DIR/traefik.yml"
chmod 644 "$TRAEFIK_CONFIG_DIR/dynamic/"*.yml

# 6. Deploy Traefik stack
print_status "Step 6: Deploying Traefik stack..."
cd "$TRAEFIK_CONFIG_DIR"

# Create docker-compose file for deployment
cat > "docker-compose.yml" << EOF
version: '3.8'

services:
  traefik:
    image: traefik:v3.0
    command:
      # API and dashboard
      - --api.dashboard=true
      - --api.insecure=false
      
      # Docker provider
      - --providers.docker.swarmMode=true
      - --providers.docker.exposedbydefault=false
      - --providers.docker.network=traefik-public
      
      # Entry points
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --entrypoints.web.http.redirections.entrypoint.to=websecure
      - --entrypoints.web.http.redirections.entrypoint.scheme=https
      
      # SSL/TLS configuration
      - --certificatesresolvers.letsencrypt.acme.email=${EMAIL}
      - --certificatesresolvers.letsencrypt.acme.storage=/certificates/acme.json
      - --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
      
      # Security headers
      - --entrypoints.websecure.http.middlewares=security-headers@file
      - --entrypoints.websecure.http.middlewares=rate-limit@file
      
      # Logging
      - --log.level=INFO
      - --accesslog=true
      - --accesslog.filepath=/var/log/traefik/access.log
      - --accesslog.format=json
      
      # Metrics
      - --metrics.prometheus=true
      - --metrics.prometheus.addEntryPointsLabels=true
      - --metrics.prometheus.addServicesLabels=true
      
      # Health checks
      - --ping=true
      - --ping.entryPoint=web
      
      # File provider for static configuration
      - --providers.file.directory=/etc/traefik/dynamic
      - --providers.file.watch=true
      
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"  # Dashboard (internal only)
      
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - traefik-certificates:/certificates
      - traefik-logs:/var/log/traefik
      - ./dynamic:/etc/traefik/dynamic:ro
      - ./traefik.yml:/etc/traefik/traefik.yml:ro
      - ./users:/etc/traefik/users:ro
      
    networks:
      - traefik-public
      
    deploy:
      placement:
        constraints:
          - node.role == manager
        preferences:
          - spread: node.labels.zone
      replicas: 2
      resources:
        limits:
          memory: 512M
          cpus: '0.5'
        reservations:
          memory: 256M
          cpus: '0.25'
      labels:
        # Traefik dashboard
        - "traefik.enable=true"
        - "traefik.http.routers.traefik-dashboard.rule=Host(\`traefik.${DOMAIN}\`)"
        - "traefik.http.routers.traefik-dashboard.entrypoints=websecure"
        - "traefik.http.routers.traefik-dashboard.tls.certresolver=letsencrypt"
        - "traefik.http.routers.traefik-dashboard.service=api@internal"
        - "traefik.http.routers.traefik-dashboard.middlewares=auth@file"
        
        # Health check
        - "traefik.http.routers.traefik-health.rule=PathPrefix(\`/ping\`)"
        - "traefik.http.routers.traefik-health.entrypoints=web"
        - "traefik.http.routers.traefik-health.service=ping@internal"
        
        # Metrics
        - "traefik.http.routers.traefik-metrics.rule=Host(\`traefik.${DOMAIN}\`) && PathPrefix(\`/metrics\`)"
        - "traefik.http.routers.traefik-metrics.entrypoints=websecure"
        - "traefik.http.routers.traefik-metrics.tls.certresolver=letsencrypt"
        - "traefik.http.routers.traefik-metrics.service=prometheus@internal"
        - "traefik.http.routers.traefik-metrics.middlewares=auth@file"
        
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
        window: 120s
      
      update_config:
        parallelism: 1
        delay: 10s
        order: start-first
        
      rollback_config:
        parallelism: 1
        delay: 5s
        order: stop-first

volumes:
  traefik-certificates:
    driver: local
  traefik-logs:
    driver: local

networks:
  traefik-public:
    external: true
EOF

# 7. Deploy the stack
print_status "Step 7: Deploying Traefik stack..."
ssh "$MANAGER_HOST" "cd $TRAEFIK_CONFIG_DIR && docker stack deploy -c docker-compose.yml traefik"

# 8. Wait for deployment
print_status "Step 8: Waiting for deployment to complete..."
sleep 30

# 9. Verify deployment
print_status "Step 9: Verifying deployment..."
ssh "$MANAGER_HOST" "docker service ls | grep traefik"
ssh "$MANAGER_HOST" "docker service ps traefik_traefik"

# 10. Test Traefik health
print_status "Step 10: Testing Traefik health..."
sleep 10

# Test HTTP to HTTPS redirect
if curl -s -I "http://$MANAGER_HOST" | grep -q "301\|302"; then
    print_status "✅ HTTP to HTTPS redirect working"
else
    print_warning "⚠️ HTTP to HTTPS redirect may not be working"
fi

# Test Traefik dashboard (internal)
if curl -s "http://$MANAGER_HOST:8080/api/rawdata" | grep -q "traefik"; then
    print_status "✅ Traefik dashboard accessible"
else
    print_warning "⚠️ Traefik dashboard may not be accessible"
fi

# 11. Create health check script
print_status "Step 11: Creating health check script..."
cat > "/opt/migration/scripts/check_traefik_health.sh" << 'EOF'
#!/bin/bash
# Check Traefik Health

set -euo pipefail

MANAGER_HOST="omv800"
DOMAIN="yourdomain.com"

echo "🏥 Checking Traefik health..."

# Check service status
echo "📋 Service status:"
ssh "$MANAGER_HOST" "docker service ls | grep traefik"

# Check service tasks
echo "🔧 Service tasks:"
ssh "$MANAGER_HOST" "docker service ps traefik_traefik"

# Check logs
echo "📝 Recent logs:"
ssh "$MANAGER_HOST" "docker service logs --tail 20 traefik_traefik"

# Test HTTP redirect
echo "🔄 Testing HTTP redirect:"
if curl -s -I "http://$MANAGER_HOST" | grep -q "301\|302"; then
    echo "✅ HTTP to HTTPS redirect working"
else
    echo "❌ HTTP to HTTPS redirect not working"
fi

# Test dashboard
echo "📊 Testing dashboard:"
if curl -s "http://$MANAGER_HOST:8080/api/rawdata" | grep -q "traefik"; then
    echo "✅ Traefik dashboard accessible"
else
    echo "❌ Traefik dashboard not accessible"
fi

# Test SSL certificate
echo "🔒 Testing SSL certificate:"
if curl -s -I "https://$MANAGER_HOST" | grep -q "HTTP/2\|HTTP/1.1 200"; then
    echo "✅ SSL certificate working"
else
    echo "❌ SSL certificate not working"
fi

echo "✅ Traefik health check completed"
EOF

chmod +x "/opt/migration/scripts/check_traefik_health.sh"

# 12. Create configuration summary
print_status "Step 12: Creating configuration summary..."
cat > "/opt/migration/traefik_summary.txt" << EOF
Traefik Deployment Summary
Generated: $(date)

Configuration:
  Domain: ${DOMAIN}
  Email: ${EMAIL}
  Manager Host: ${MANAGER_HOST}

Services Configured:
  - Immich Photo Management: https://immich.${DOMAIN}
  - Jellyfin Media Server: https://jellyfin.${DOMAIN}
  - Home Assistant: https://home.${DOMAIN}
  - AppFlowy Collaboration: https://appflowy.${DOMAIN}
  - Paperless Documents: https://paperless.${DOMAIN}
  - Portainer Management: https://portainer.${DOMAIN}
  - Grafana Monitoring: https://grafana.${DOMAIN}
  - Prometheus Metrics: https://prometheus.${DOMAIN}
  - Uptime Kuma: https://uptime.${DOMAIN}
  - Traefik Dashboard: https://traefik.${DOMAIN}

Security Features:
  - SSL/TLS with Let's Encrypt
  - Security headers
  - Rate limiting
  - Basic authentication
  - IP whitelisting
  - CORS support

Monitoring:
  - Prometheus metrics
  - Access logging
  - Health checks
  - Dashboard

Configuration Files:
  - Static config: ${TRAEFIK_CONFIG_DIR}/traefik.yml
  - Dynamic config: ${TRAEFIK_CONFIG_DIR}/dynamic/
  - Users file: ${TRAEFIK_CONFIG_DIR}/users
  - Health check: /opt/migration/scripts/check_traefik_health.sh

Next Steps:
1. Update DNS records to point to ${MANAGER_HOST}
2. Test SSL certificate generation
3. Deploy monitoring stack
4. Begin service migration
EOF

print_status "✅ Traefik deployment completed successfully!"
print_status "📋 Configuration summary saved to: /opt/migration/traefik_summary.txt"
print_status "🔧 Health check script: /opt/migration/scripts/check_traefik_health.sh"

echo ""
print_status "Next steps:"
echo "  1. Update DNS: Point *.${DOMAIN} to ${MANAGER_HOST}"
echo "  2. Test SSL: ./scripts/check_traefik_health.sh"
echo "  3. Deploy monitoring: ./scripts/setup_monitoring.sh"
echo "  4. Begin migration: ./scripts/start_migration.sh"
