#!/bin/bash

# SSL Certificate Management для CatLink
# Автоматическая настройка SSL с Let's Encrypt и управление сертификатами

set -e

# Цвета
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

log() { echo -e "${BLUE}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1"; }
success() { echo -e "${GREEN}✅ $1${NC}"; }
warning() { echo -e "${YELLOW}⚠️  $1${NC}"; }
error() { echo -e "${RED}❌ $1${NC}"; exit 1; }

# Проверка переменных окружения
check_env() {
    if [ ! -f ".env" ]; then
        error ".env файл не найден. Запустите make deploy для его создания."
    fi
    
    source .env
    
    if [ -z "$MAIN_DOMAIN" ]; then
        error "MAIN_DOMAIN не задан в .env файле"
    fi
    
    if [ -z "$LETSENCRYPT_EMAIL" ]; then
        error "LETSENCRYPT_EMAIL не задан в .env файле"
    fi
}

# Установка certbot если не установлен
install_certbot() {
    if ! command -v certbot &> /dev/null; then
        log "Установка certbot..."
        sudo apt update
        sudo apt install -y certbot python3-certbot-nginx
        success "certbot установлен"
    else
        success "certbot уже установлен"
    fi
}

# Проверка DNS записей
check_dns() {
    log "Проверка DNS записей для $MAIN_DOMAIN..."
    
    # Получаем внешний IP сервера
    SERVER_IP=$(curl -s https://ipinfo.io/ip || curl -s https://icanhazip.com || echo "unknown")
    log "IP сервера: $SERVER_IP"
    
    # Проверяем A запись
    DOMAIN_IP=$(nslookup $MAIN_DOMAIN | grep -A 1 "Name:" | tail -n1 | awk '{print $2}' || echo "unknown")
    log "IP домена $MAIN_DOMAIN: $DOMAIN_IP"
    
    if [ "$SERVER_IP" = "$DOMAIN_IP" ]; then
        success "DNS запись настроена корректно"
        return 0
    else
        warning "DNS запись может быть настроена неверно"
        warning "Сервер: $SERVER_IP, Домен: $DOMAIN_IP"
        read -p "Продолжить? (yes/no): " CONTINUE
        if [ "$CONTINUE" != "yes" ]; then
            error "Настройте DNS запись и попробуйте снова"
        fi
    fi
}

# Получение Let's Encrypt сертификата
obtain_letsencrypt() {
    log "Получение Let's Encrypt сертификата для $MAIN_DOMAIN..."
    
    # Формируем список доменов
    CERT_DOMAINS="-d $MAIN_DOMAIN"
    if [ -n "$ADDITIONAL_DOMAINS" ]; then
        IFS=',' read -ra DOMAINS <<< "$ADDITIONAL_DOMAINS"
        for domain in "${DOMAINS[@]}"; do
            domain=$(echo $domain | xargs) # trim whitespace
            if [ -n "$domain" ]; then
                CERT_DOMAINS="$CERT_DOMAINS -d $domain"
                log "Добавлен домен: $domain"
            fi
        done
    fi
    
    log "Домены для сертификата: $CERT_DOMAINS"
    
    # Временно останавливаем nginx для standalone режима
    if systemctl is-active --quiet nginx; then
        log "Остановка nginx для получения сертификата..."
        sudo systemctl stop nginx
        NGINX_WAS_RUNNING=true
    else
        NGINX_WAS_RUNNING=false
    fi
    
    # Получаем сертификат в standalone режиме
    if sudo certbot certonly --standalone \
        $CERT_DOMAINS \
        --email "$LETSENCRYPT_EMAIL" \
        --agree-tos \
        --non-interactive \
        --expand; then
        
        success "Сертификат получен успешно"
        
        # Запускаем nginx обратно
        if [ "$NGINX_WAS_RUNNING" = true ]; then
            sudo systemctl start nginx
        fi
        
        return 0
    else
        error "Не удалось получить сертификат"
    fi
}

# Создание самоподписанного сертификата
create_selfsigned() {
    log "Создание самоподписанного сертификата для $MAIN_DOMAIN..."
    
    # Создаем директории
    sudo mkdir -p /etc/ssl/private /etc/ssl/certs
    
    # Генерируем ключ и сертификат
    sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
        -keyout "/etc/ssl/private/${MAIN_DOMAIN}.key" \
        -out "/etc/ssl/certs/${MAIN_DOMAIN}.crt" \
        -subj "/C=US/ST=State/L=City/O=CatLink/CN=${MAIN_DOMAIN}" \
        -extensions v3_req \
        -config <(cat <<EOF
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no

[req_distinguished_name]
CN = ${MAIN_DOMAIN}

[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1 = ${MAIN_DOMAIN}
EOF
    )
    
    # Устанавливаем права
    sudo chmod 600 "/etc/ssl/private/${MAIN_DOMAIN}.key"
    sudo chmod 644 "/etc/ssl/certs/${MAIN_DOMAIN}.crt"
    
    success "Самоподписанный сертификат создан"
}

# Обновление nginx конфигурации для SSL
update_nginx_ssl() {
    local ssl_type=$1
    
    log "Обновление nginx конфигурации для SSL ($ssl_type)..."
    
    if [ "$ssl_type" = "letsencrypt" ]; then
        SSL_CERT="/etc/letsencrypt/live/${MAIN_DOMAIN}/fullchain.pem"
        SSL_KEY="/etc/letsencrypt/live/${MAIN_DOMAIN}/privkey.pem"
    else
        SSL_CERT="/etc/ssl/certs/${MAIN_DOMAIN}.crt"
        SSL_KEY="/etc/ssl/private/${MAIN_DOMAIN}.key"
    fi
    
    # Создаем SSL конфигурацию
    sudo tee /etc/nginx/sites-available/catlink-ssl << EOF
# CatLink SSL nginx configuration
# Generated $(date)

# HTTP -> HTTPS redirect
server {
    listen 80;
    server_name $MAIN_DOMAIN${ADDITIONAL_DOMAINS:+ $ADDITIONAL_DOMAINS};
    
    # Let's Encrypt challenge
    location /.well-known/acme-challenge/ {
        root /var/www/html;
    }
    
    # Redirect all other requests to HTTPS
    location / {
        return 301 https://\$server_name\$request_uri;
    }
}

# HTTPS server
server {
    listen 443 ssl http2;
    server_name $MAIN_DOMAIN${ADDITIONAL_DOMAINS:+ $ADDITIONAL_DOMAINS};
    
    # SSL Configuration
    ssl_certificate $SSL_CERT;
    ssl_certificate_key $SSL_KEY;
    
    # SSL Security
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    
    # Security headers
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "no-referrer-when-downgrade" always;
    add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
    
    # Gzip compression
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
    
    # Frontend (Next.js)
    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade \$http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
        proxy_cache_bypass \$http_upgrade;
        
        # Timeout settings
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
    
    # Backend API
    location /api/ {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
        
        # Timeout settings
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
    
    # Admin interface
    location /admin/ {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
    }
    
    # Static files
    location /static/ {
        proxy_pass http://127.0.0.1:8000;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
    
    # Media files
    location /media/ {
        proxy_pass http://127.0.0.1:8000;
        expires 1y;
        add_header Cache-Control "public";
    }
    
    # Security
    location ~ /\\.ht {
        deny all;
    }
    
    location = /robots.txt {
        proxy_pass http://127.0.0.1:8000;
        access_log off;
    }
    
    location = /favicon.ico {
        proxy_pass http://127.0.0.1:3000;
        access_log off;
    }
}
EOF

    # Включаем SSL конфигурацию
    sudo ln -sf /etc/nginx/sites-available/catlink-ssl /etc/nginx/sites-enabled/catlink
    
    # Проверяем конфигурацию
    if sudo nginx -t; then
        success "Конфигурация nginx обновлена"
        sudo systemctl reload nginx
    else
        error "Ошибка в конфигурации nginx"
    fi
}

# Настройка автообновления сертификатов
setup_auto_renewal() {
    log "Настройка автообновления Let's Encrypt сертификатов..."
    
    # Создаем скрипт обновления
    sudo tee /usr/local/bin/certbot-renew-catlink << 'EOF'
#!/bin/bash
# CatLink SSL certificate renewal script

certbot renew --quiet --pre-hook "systemctl stop nginx" --post-hook "systemctl start nginx"

# Проверяем успешность обновления
if [ $? -eq 0 ]; then
    echo "$(date): SSL certificates renewed successfully" >> /var/log/catlink-ssl.log
else
    echo "$(date): SSL certificate renewal failed" >> /var/log/catlink-ssl.log
fi
EOF

    sudo chmod +x /usr/local/bin/certbot-renew-catlink
    
    # Добавляем в crontab
    (sudo crontab -l 2>/dev/null | grep -v certbot-renew-catlink; echo "0 12 * * * /usr/local/bin/certbot-renew-catlink") | sudo crontab -
    
    success "Автообновление сертификатов настроено"
}

# Проверка статуса SSL
check_ssl_status() {
    log "Проверка статуса SSL..."
    
    if [ -f "/etc/letsencrypt/live/${MAIN_DOMAIN}/fullchain.pem" ]; then
        CERT_EXPIRY=$(openssl x509 -enddate -noout -in "/etc/letsencrypt/live/${MAIN_DOMAIN}/fullchain.pem" | cut -d= -f2)
        success "Let's Encrypt сертификат активен до: $CERT_EXPIRY"
    elif [ -f "/etc/ssl/certs/${MAIN_DOMAIN}.crt" ]; then
        CERT_EXPIRY=$(openssl x509 -enddate -noout -in "/etc/ssl/certs/${MAIN_DOMAIN}.crt" | cut -d= -f2)
        warning "Самоподписанный сертификат активен до: $CERT_EXPIRY"
    else
        error "SSL сертификат не найден"
    fi
    
    # Проверяем HTTPS соединение
    if command -v curl &> /dev/null; then
        if curl -s -I "https://${MAIN_DOMAIN}" | grep -q "HTTP"; then
            success "HTTPS соединение работает"
        else
            warning "HTTPS соединение может не работать"
        fi
    fi
}

# Основное меню
main() {
    echo "🔒 ===== CatLink SSL Certificate Manager ====="
    echo ""
    
    check_env
    
    echo "Выберите действие:"
    echo "1) Получить Let's Encrypt сертификат (рекомендуется)"
    echo "2) Создать самоподписанный сертификат (для тестирования)"
    echo "3) Проверить статус существующих сертификатов"
    echo "4) Настроить автообновление"
    echo "5) Обновить nginx конфигурацию"
    echo ""
    read -p "Выберите опцию (1-5): " choice
    
    case $choice in
        1)
            install_certbot
            check_dns
            obtain_letsencrypt
            update_nginx_ssl "letsencrypt"
            setup_auto_renewal
            check_ssl_status
            ;;
        2)
            create_selfsigned
            update_nginx_ssl "selfsigned"
            check_ssl_status
            ;;
        3)
            check_ssl_status
            ;;
        4)
            setup_auto_renewal
            ;;
        5)
            echo "Какой тип SSL использовать?"
            echo "1) Let's Encrypt"
            echo "2) Самоподписанный"
            read -p "Выберите (1-2): " ssl_type
            if [ "$ssl_type" = "1" ]; then
                update_nginx_ssl "letsencrypt"
            else
                update_nginx_ssl "selfsigned"
            fi
            ;;
        *)
            error "Неверный выбор"
            ;;
    esac
    
    echo ""
    success "SSL настройка завершена!"
    echo ""
    echo "🌐 Проверьте сайт: https://${MAIN_DOMAIN}"
}

# Запуск
main "$@"