#!/bin/bash
# Setup Secrets Management
# This script implements Docker secrets and environment-based configuration

set -euo pipefail

echo "🔐 Setting up secrets management..."

# Colors 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}[WARNING]${NC} $1"
}

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

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

# Configuration
MANAGER_HOST="omv800"
SECRETS_DIR="/opt/migration/secrets"
CONFIG_DIR="/opt/migration/configs"
ENV_FILE="/opt/migration/.env"

# 1. Create secrets directory with proper permissions
print_step "Step 1: Creating secrets directory structure..."
mkdir -p "$SECRETS_DIR/generated"
mkdir -p "$SECRETS_DIR/templates" 
chmod 700 "$SECRETS_DIR"
chmod 700 "$SECRETS_DIR/generated"

# 2. Generate strong passwords and keys
print_step "Step 2: Generating secure passwords and keys..."

# Function to generate secure passwords
generate_password() {
    openssl rand -base64 32 | tr -d "=+/" | cut -c1-25
}

# Generate passwords
TRAEFIK_ADMIN_PASSWORD=$(generate_password)
TRAEFIK_MIGRATION_PASSWORD=$(generate_password)
POSTGRES_PASSWORD=$(generate_password)
REDIS_PASSWORD=$(generate_password)
JWT_SECRET=$(openssl rand -base64 64 | tr -d "=+/")

# Generate htpasswd hashes
TRAEFIK_ADMIN_HASH=$(htpasswd -nbB admin "$TRAEFIK_ADMIN_PASSWORD" | cut -d: -f2)
TRAEFIK_MIGRATION_HASH=$(htpasswd -nbB migration "$TRAEFIK_MIGRATION_PASSWORD" | cut -d: -f2)

print_status "Generated secure passwords and hashes"

# 3. Create environment configuration file
print_step "Step 3: Creating environment configuration..."
cat > "$ENV_FILE" << EOF
# Migration Environment Configuration
# Generated: $(date)
# IMPORTANT: This file contains sensitive information - do not commit to version control

# Domain Configuration
DOMAIN=homelab.local
EMAIL=admin@homelab.local
TIMEZONE=America/New_York

# Network Configuration
MANAGER_HOST=omv800
MANAGER_IP=192.168.50.229

# Database Configuration
POSTGRES_USER=postgres
POSTGRES_DB=migration_db
REDIS_USER=default

# SSL Configuration
SSL_KEY_SIZE=4096
SSL_COUNTRY=US
SSL_STATE=State
SSL_CITY=City
SSL_ORG=HomeLab
SSL_OU=IT

# Monitoring Configuration
GRAFANA_ADMIN_USER=admin
PROMETHEUS_RETENTION=30d

# Backup Configuration
BACKUP_RETENTION_DAYS=30
BACKUP_COMPRESSION=gzip

# Security Configuration
SESSION_TIMEOUT=3600
MAX_LOGIN_ATTEMPTS=5
LOCKOUT_DURATION=900

# Feature Flags
ENABLE_METRICS=true
ENABLE_DEBUG=false
ENABLE_TRACING=false
EOF

# Add sensitive values (these will be moved to Docker secrets)
cat >> "$ENV_FILE" << EOF

# Sensitive Configuration (will be moved to Docker secrets)
TRAEFIK_ADMIN_PASSWORD=$TRAEFIK_ADMIN_PASSWORD
TRAEFIK_MIGRATION_PASSWORD=$TRAEFIK_MIGRATION_PASSWORD
POSTGRES_PASSWORD=$POSTGRES_PASSWORD
REDIS_PASSWORD=$REDIS_PASSWORD
JWT_SECRET=$JWT_SECRET
EOF

chmod 600 "$ENV_FILE"
print_status "Environment configuration created: $ENV_FILE"

# 4. Create Docker secrets
print_step "Step 4: Creating Docker secrets..."

# Create secret files
echo -n "$TRAEFIK_ADMIN_PASSWORD" > "$SECRETS_DIR/generated/traefik_admin_password"
echo -n "$TRAEFIK_MIGRATION_PASSWORD" > "$SECRETS_DIR/generated/traefik_migration_password"
echo -n "$POSTGRES_PASSWORD" > "$SECRETS_DIR/generated/postgres_password"
echo -n "$REDIS_PASSWORD" > "$SECRETS_DIR/generated/redis_password"
echo -n "$JWT_SECRET" > "$SECRETS_DIR/generated/jwt_secret"

# Create users file for Traefik
cat > "$SECRETS_DIR/generated/traefik_users" << EOF
admin:\$2y\$10\$$TRAEFIK_ADMIN_HASH
migration:\$2y\$10\$$TRAEFIK_MIGRATION_HASH
EOF

# Set proper permissions
chmod 600 "$SECRETS_DIR"/generated/*

# Deploy secrets to Docker Swarm
ssh "$MANAGER_HOST" "docker secret rm traefik_admin_password 2>/dev/null || true"
ssh "$MANAGER_HOST" "docker secret rm traefik_migration_password 2>/dev/null || true"
ssh "$MANAGER_HOST" "docker secret rm postgres_password 2>/dev/null || true"
ssh "$MANAGER_HOST" "docker secret rm redis_password 2>/dev/null || true"
ssh "$MANAGER_HOST" "docker secret rm jwt_secret 2>/dev/null || true"
ssh "$MANAGER_HOST" "docker secret rm traefik_users 2>/dev/null || true"

# Copy secrets to manager and create Docker secrets
scp "$SECRETS_DIR/generated/traefik_admin_password" "$MANAGER_HOST:/tmp/"
scp "$SECRETS_DIR/generated/traefik_migration_password" "$MANAGER_HOST:/tmp/"
scp "$SECRETS_DIR/generated/postgres_password" "$MANAGER_HOST:/tmp/"
scp "$SECRETS_DIR/generated/redis_password" "$MANAGER_HOST:/tmp/"
scp "$SECRETS_DIR/generated/jwt_secret" "$MANAGER_HOST:/tmp/"
scp "$SECRETS_DIR/generated/traefik_users" "$MANAGER_HOST:/tmp/"

ssh "$MANAGER_HOST" "docker secret create traefik_admin_password /tmp/traefik_admin_password"
ssh "$MANAGER_HOST" "docker secret create traefik_migration_password /tmp/traefik_migration_password"
ssh "$MANAGER_HOST" "docker secret create postgres_password /tmp/postgres_password"
ssh "$MANAGER_HOST" "docker secret create redis_password /tmp/redis_password"
ssh "$MANAGER_HOST" "docker secret create jwt_secret /tmp/jwt_secret"
ssh "$MANAGER_HOST" "docker secret create traefik_users /tmp/traefik_users"

# Clean up temporary files on manager
ssh "$MANAGER_HOST" "rm -f /tmp/traefik_admin_password /tmp/traefik_migration_password /tmp/postgres_password /tmp/redis_password /tmp/jwt_secret /tmp/traefik_users"

print_status "Docker secrets created successfully"

# 5. Create secure configuration templates
print_step "Step 5: Creating secure configuration templates..."

# Updated Traefik configuration template
cat > "$SECRETS_DIR/templates/traefik-secure.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
      - --global.sendanonymoususage=false
      - --global.checknewversion=false
      
      # Logging
      - --log.level=INFO
      - --log.format=json
      - --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"
      
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - traefik-certificates:/certificates
      - traefik-logs:/var/log/traefik
      - ./dynamic:/etc/traefik/dynamic:ro
      
    secrets:
      - traefik_users
      
    networks:
      - traefik-public
      
    environment:
      - DOMAIN=${DOMAIN}
      - EMAIL=${EMAIL}
      
    deploy:
      placement:
        constraints:
          - node.role == manager
      replicas: 2
      resources:
        limits:
          memory: 512M
          cpus: '0.5'
        reservations:
          memory: 256M
          cpus: '0.25'
      labels:
        # Traefik dashboard with secret-based auth
        - "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-secure@file"
        
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
        window: 120s

secrets:
  traefik_users:
    external: true

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

networks:
  traefik-public:
    external: true
EOF

# Updated middleware configuration with secrets
cat > "$SECRETS_DIR/templates/middleware-secure.yml" << 'EOF'
# Traefik Dynamic Configuration - Secure Middleware
# Uses Docker secrets for authentication

http:
  middlewares:
    # Secure authentication middleware using Docker secrets
    auth-secure:
      basicAuth:
        usersFile: "/run/secrets/traefik_users"
        removeHeader: true
        realm: "HomeLabSecure"
    
    # Enhanced security headers
    security-headers-enhanced:
      headers:
        # Security headers
        frameDeny: true
        sslRedirect: true
        browserXssFilter: true
        contentTypeNosniff: true
        forceSTSHeader: true
        sslForceHost: true
        stsIncludeSubdomains: true
        stsPreload: true
        stsSeconds: 63072000  # 2 years
        customFrameOptionsValue: "SAMEORIGIN"
        customRequestHeaders:
          X-Forwarded-Proto: "https"
        customResponseHeaders:
          X-Robots-Tag: "none"
          X-Content-Type-Options: "nosniff"
          X-Frame-Options: "SAMEORIGIN"
          X-XSS-Protection: "1; mode=block"
          Referrer-Policy: "strict-origin-when-cross-origin"
          Permissions-Policy: "camera=(), microphone=(), geolocation=(), payment=()"
          Content-Security-Policy: "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'"
    
    # Stricter rate limiting for production
    rate-limit-strict:
      rateLimit:
        burst: 20
        average: 10
        period: "1s"
        sourceCriterion:
          ipStrategy:
            depth: 1
    
    # IP whitelist for admin interfaces
    ip-whitelist-strict:
      ipWhiteList:
        sourceRange:
          - "192.168.50.0/24"  # Local network only
        ipStrategy:
          depth: 1
          excludedIPs:
            - "127.0.0.1"
EOF

print_status "Secure configuration templates created"

# 6. Create script to update existing configurations
print_step "Step 6: Creating configuration update script..."
cat > "/opt/migration/scripts/update_configurations.sh" << 'EOF'
#!/bin/bash
# Update existing configurations to use secrets management

set -euo pipefail

# Load environment variables
source /opt/migration/.env

echo "🔧 Updating configurations to use secrets management..."

# Update Traefik deployment
echo "Updating Traefik configuration..."
envsubst < /opt/migration/secrets/templates/traefik-secure.yml > /opt/migration/configs/traefik/docker-compose-secure.yml

# Update middleware configuration  
cp /opt/migration/secrets/templates/middleware-secure.yml /opt/migration/configs/traefik/dynamic/middleware-secure.yml

# Create deployment script with secrets
cat > /opt/migration/scripts/deploy_traefik_secure.sh << 'SCRIPT_EOF'
#!/bin/bash
# Deploy Traefik with secrets management

set -euo pipefail
source /opt/migration/.env

echo "🌐 Deploying Traefik with secrets management..."

cd /opt/migration/configs/traefik
docker stack deploy -c docker-compose-secure.yml traefik-secure

echo "✅ Traefik deployed with secrets management"
SCRIPT_EOF

chmod +x /opt/migration/scripts/deploy_traefik_secure.sh

echo "✅ Configurations updated successfully"
EOF

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

# 7. Create secrets rotation script
print_step "Step 7: Creating secrets rotation script..."
cat > "/opt/migration/scripts/rotate_secrets.sh" << 'EOF'
#!/bin/bash
# Rotate Docker secrets safely

set -euo pipefail

echo "🔄 Rotating Docker secrets..."

MANAGER_HOST="omv800"
SECRETS_DIR="/opt/migration/secrets"

# Function to rotate a secret
rotate_secret() {
    local secret_name=$1
    local secret_file=$2
    
    echo "Rotating secret: $secret_name"
    
    # Generate new secret value
    case $secret_name in
        "*password*")
            new_value=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-25)
            ;;
        "jwt_secret")
            new_value=$(openssl rand -base64 64 | tr -d "=+/")
            ;;
        *)
            echo "Unknown secret type: $secret_name"
            return 1
            ;;
    esac
    
    # Create new secret file
    echo -n "$new_value" > "$secret_file.new"
    chmod 600 "$secret_file.new"
    
    # Create new Docker secret
    ssh "$MANAGER_HOST" "docker secret create ${secret_name}_new /tmp/${secret_name}.new"
    
    # Update services to use new secret (this would need service-specific logic)
    echo "⚠️  Manual service update required for $secret_name"
    
    # After successful deployment, remove old secret
    # ssh "$MANAGER_HOST" "docker secret rm $secret_name"
    # ssh "$MANAGER_HOST" "docker secret create $secret_name /tmp/${secret_name}.new" 
    
    echo "✅ Secret $secret_name rotated successfully"
}

echo "⚠️  Secret rotation requires manual service updates"
echo "Use this script as a template for implementing zero-downtime secret rotation"
EOF

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

# 8. Create secrets backup script
print_step "Step 8: Creating secrets backup script..."
cat > "/opt/migration/scripts/backup_secrets.sh" << 'EOF'
#!/bin/bash
# Backup secrets securely

set -euo pipefail

echo "💾 Backing up secrets..."

BACKUP_DIR="/opt/migration/backups/secrets/$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"

# Backup environment file (encrypted)
gpg --cipher-algo AES256 --compress-algo 1 --s2k-mode 3 \
    --s2k-digest-algo SHA512 --s2k-count 65536 --symmetric \
    --output "$BACKUP_DIR/.env.gpg" /opt/migration/.env

# Backup secret files (encrypted)
tar czf - /opt/migration/secrets/generated | \
    gpg --cipher-algo AES256 --compress-algo 1 --s2k-mode 3 \
        --s2k-digest-algo SHA512 --s2k-count 65536 --symmetric \
        --output "$BACKUP_DIR/secrets.tar.gz.gpg"

# Set secure permissions
chmod 700 "$BACKUP_DIR"
chmod 600 "$BACKUP_DIR"/*

echo "✅ Secrets backed up to: $BACKUP_DIR"
echo "ℹ️  Use GPG to decrypt: gpg --decrypt file.gpg"
EOF

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

# 9. Create validation script
print_step "Step 9: Creating secrets validation script..."
cat > "/opt/migration/scripts/validate_secrets.sh" << 'EOF'
#!/bin/bash
# Validate secrets configuration

set -euo pipefail

echo "✅ Validating secrets configuration..."

MANAGER_HOST="omv800"
ENV_FILE="/opt/migration/.env"
SECRETS_DIR="/opt/migration/secrets"

# Check if environment file exists and is readable
if [[ -r "$ENV_FILE" ]]; then
    echo "✅ Environment file exists and is readable"
else
    echo "❌ Environment file missing or not readable"
    exit 1
fi

# Check if secrets directory has correct permissions
if [[ -d "$SECRETS_DIR" ]] && [[ $(stat -c %a "$SECRETS_DIR") == "700" ]]; then
    echo "✅ Secrets directory has correct permissions"
else
    echo "❌ Secrets directory permissions incorrect"
    exit 1
fi

# Check if Docker secrets exist
echo "Checking Docker secrets..."
secrets=(
    "traefik_admin_password"
    "traefik_migration_password" 
    "postgres_password"
    "redis_password"
    "jwt_secret"
    "traefik_users"
)

for secret in "${secrets[@]}"; do
    if ssh "$MANAGER_HOST" "docker secret ls | grep -q $secret"; then
        echo "✅ Docker secret exists: $secret"
    else
        echo "❌ Docker secret missing: $secret"
        exit 1
    fi
done

# Validate environment variables
source "$ENV_FILE"
required_vars=(
    "DOMAIN"
    "EMAIL" 
    "MANAGER_HOST"
    "POSTGRES_PASSWORD"
)

for var in "${required_vars[@]}"; do
    if [[ -n "${!var}" ]]; then
        echo "✅ Environment variable set: $var"
    else
        echo "❌ Environment variable missing: $var"
        exit 1
    fi
done

echo "✅ All secrets validation checks passed"
EOF

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

# 10. Create summary
print_step "Step 10: Creating setup summary..."
cat > "/opt/migration/secrets_setup_summary.txt" << EOF
Secrets Management Setup Summary
Generated: $(date)

Files Created:
  - Environment config: $ENV_FILE
  - Secrets directory: $SECRETS_DIR/
  - Traefik secure template: $SECRETS_DIR/templates/traefik-secure.yml
  - Middleware secure template: $SECRETS_DIR/templates/middleware-secure.yml
  
Scripts Created:
  - Update configurations: /opt/migration/scripts/update_configurations.sh
  - Rotate secrets: /opt/migration/scripts/rotate_secrets.sh
  - Backup secrets: /opt/migration/scripts/backup_secrets.sh
  - Validate secrets: /opt/migration/scripts/validate_secrets.sh

Docker Secrets Created:
  - traefik_admin_password
  - traefik_migration_password
  - postgres_password
  - redis_password
  - jwt_secret
  - traefik_users

Generated Credentials:
  - Traefik Admin User: admin
  - Traefik Admin Password: $TRAEFIK_ADMIN_PASSWORD
  - Traefik Migration User: migration
  - Traefik Migration Password: $TRAEFIK_MIGRATION_PASSWORD
  - PostgreSQL Password: $POSTGRES_PASSWORD
  - Redis Password: $REDIS_PASSWORD

Next Steps:
1. Update .gitignore to exclude $ENV_FILE
2. Run: /opt/migration/scripts/update_configurations.sh
3. Run: /opt/migration/scripts/validate_secrets.sh
4. Deploy with: /opt/migration/scripts/deploy_traefik_secure.sh

Security Notes:
- All passwords are 25 characters with high entropy
- Secrets are stored in Docker secrets (encrypted at rest)
- Environment file has 600 permissions
- Backup scripts use GPG encryption
- Rotation scripts provided for regular updates
EOF

print_status "✅ Secrets management setup completed successfully!"
print_status "📋 Summary saved to: /opt/migration/secrets_setup_summary.txt"

echo ""
print_status "Generated credentials (SAVE THESE SECURELY):"
echo "  Traefik Admin: admin / $TRAEFIK_ADMIN_PASSWORD"
echo "  Traefik Migration: migration / $TRAEFIK_MIGRATION_PASSWORD"
echo ""
print_warning "Remember to:"
echo "  1. Add $ENV_FILE to .gitignore"
echo "  2. Store credentials in password manager"
echo "  3. Run validation: /opt/migration/scripts/validate_secrets.sh"