#!/bin/bash
# ==============================================================================
# Wordly.art - NPM Failover via API
# ==============================================================================
# Automatically updates Nginx Proxy Manager's forward host via its REST API.
# Called by disaster-recovery.sh after a successful health check on the new server.
#
# Usage:
#   ./npm-failover.sh --target-ip 192.168.1.98         # Switch to new server
#   ./npm-failover.sh --target-ip 192.168.1.151        # Rollback to original server
#   ./npm-failover.sh --dry-run --target-ip 192.168.1.98  # Test without modifying NPM
# ==============================================================================

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

log()         { echo -e "[NPM-Failover ${TIMESTAMP}] $1"; }
log_success() { echo -e "[NPM-Failover ${TIMESTAMP}] ${GREEN}$1${NC}"; }
log_warning() { echo -e "[NPM-Failover ${TIMESTAMP}] ${YELLOW}WARNING: $1${NC}"; }
log_error()   { echo -e "[NPM-Failover ${TIMESTAMP}] ${RED}ERROR: $1${NC}"; }
log_info()    { echo -e "[NPM-Failover ${TIMESTAMP}] ${BLUE}$1${NC}"; }

# ==============================================================================
# 1. LOAD CONFIGURATION FROM .env
# ==============================================================================
ENV_FILE="${PROJECT_ROOT}/.env"
if [ -f "${ENV_FILE}" ]; then
    set -a
    set +u
    source "${ENV_FILE}"
    set -u
    set +a
fi

NPM_API_URL="${NPM_API_URL:-}"
NPM_ADMIN_EMAIL="${NPM_ADMIN_EMAIL:-}"
NPM_ADMIN_PASSWORD="${NPM_ADMIN_PASSWORD:-}"
NPM_PROXY_HOST_DOMAIN="${NPM_PROXY_HOST_DOMAIN:-wordly.art}"
TELEGRAM_BOT_TOKEN="${TELEGRAM_BOT_TOKEN:-}"
TELEGRAM_CHAT_ID="${TELEGRAM_CHAT_ID:-}"

# ==============================================================================
# 2. ARGUMENT PARSING
# ==============================================================================
TARGET_IP=""
DRY_RUN=false

while [[ $# -gt 0 ]]; do
    case "$1" in
        --target-ip)
            TARGET_IP="$2"
            shift 2
            ;;
        --dry-run)
            DRY_RUN=true
            shift
            ;;
        *)
            log_error "Unknown argument: $1"
            echo "Usage: $0 --target-ip <IP> [--dry-run]"
            exit 1
            ;;
    esac
done

# ==============================================================================
# 3. VALIDATION
# ==============================================================================
validate_config() {
    local errors=0

    if [ -z "${TARGET_IP}" ]; then
        log_error "--target-ip is required."
        errors=$((errors + 1))
    fi
    if [ -z "${NPM_API_URL}" ]; then
        log_error "NPM_API_URL is not set in .env (example: http://192.168.1.184:81/api)"
        errors=$((errors + 1))
    fi
    if [ -z "${NPM_ADMIN_EMAIL}" ]; then
        log_error "NPM_ADMIN_EMAIL is not set in .env"
        errors=$((errors + 1))
    fi
    if [ -z "${NPM_ADMIN_PASSWORD}" ]; then
        log_error "NPM_ADMIN_PASSWORD is not set in .env"
        errors=$((errors + 1))
    fi

    if ! command -v curl &>/dev/null; then
        log_error "curl is not installed. Required for NPM API calls."
        errors=$((errors + 1))
    fi
    if ! command -v jq &>/dev/null; then
        log_error "jq is not installed. Required for JSON parsing. Install: apt-get install jq"
        errors=$((errors + 1))
    fi

    if [ "${errors}" -gt 0 ]; then
        exit 1
    fi
}

# ==============================================================================
# 4. TELEGRAM NOTIFICATION
# ==============================================================================
send_telegram() {
    local message="$1"
    if [ -n "${TELEGRAM_BOT_TOKEN}" ] && [ -n "${TELEGRAM_CHAT_ID}" ]; then
        curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
            -d "chat_id=${TELEGRAM_CHAT_ID}" \
            -d "text=${message}" \
            -d "parse_mode=Markdown" \
            >/dev/null 2>&1 || true
    fi
}

# ==============================================================================
# 5. NPM API AUTHENTICATION
# ==============================================================================
npm_authenticate() {
    log "Authenticating with NPM API at ${NPM_API_URL}..."

    local response
    response=$(curl -s -w "\n%{http_code}" \
        -X POST "${NPM_API_URL}/tokens" \
        -H "Content-Type: application/json" \
        -d "{\"identity\": \"${NPM_ADMIN_EMAIL}\", \"secret\": \"${NPM_ADMIN_PASSWORD}\"}" \
        --connect-timeout 10 \
        --max-time 15)

    local http_code
    http_code=$(echo "${response}" | tail -n1)
    local body
    body=$(echo "${response}" | head -n-1)

    if [ "${http_code}" != "200" ]; then
        log_error "NPM authentication failed (HTTP ${http_code}). Check NPM_ADMIN_EMAIL and NPM_ADMIN_PASSWORD."
        log_error "Response: ${body}"
        return 1
    fi

    local token
    token=$(echo "${body}" | jq -r '.token // empty')
    if [ -z "${token}" ]; then
        log_error "Could not extract token from NPM response."
        log_error "Response: ${body}"
        return 1
    fi

    log_success "NPM authentication successful."
    echo "${token}"
}

# ==============================================================================
# 6. FIND PROXY HOST BY DOMAIN
# ==============================================================================
npm_find_proxy_host() {
    local token="$1"
    log "Looking up proxy host for domain: ${NPM_PROXY_HOST_DOMAIN}..."

    local response
    response=$(curl -s -w "\n%{http_code}" \
        -X GET "${NPM_API_URL}/nginx/proxy-hosts?expand=domain_names" \
        -H "Authorization: Bearer ${token}" \
        --connect-timeout 10 \
        --max-time 15)

    local http_code
    http_code=$(echo "${response}" | tail -n1)
    local body
    body=$(echo "${response}" | head -n-1)

    if [ "${http_code}" != "200" ]; then
        log_error "Failed to retrieve proxy hosts (HTTP ${http_code})"
        return 1
    fi

    # Find the proxy host ID matching our domain
    local host_id
    host_id=$(echo "${body}" | jq -r \
        --arg domain "${NPM_PROXY_HOST_DOMAIN}" \
        '.[] | select(.domain_names[] == $domain) | .id' | head -n1)

    if [ -z "${host_id}" ]; then
        log_error "No proxy host found for domain '${NPM_PROXY_HOST_DOMAIN}' in NPM."
        log_error "Available domains:"
        echo "${body}" | jq -r '.[].domain_names[]' | sed 's/^/  - /' >&2
        return 1
    fi

    log_success "Found proxy host ID: ${host_id} for ${NPM_PROXY_HOST_DOMAIN}"

    # Also retrieve current forward_host for logging
    local current_host
    current_host=$(echo "${body}" | jq -r \
        --arg domain "${NPM_PROXY_HOST_DOMAIN}" \
        '.[] | select(.domain_names[] == $domain) | .forward_host' | head -n1)
    log_info "Current forward host: ${current_host}"

    echo "${host_id}|${current_host}"
}

# ==============================================================================
# 7. UPDATE PROXY HOST FORWARD IP
# ==============================================================================
npm_update_proxy_host() {
    local token="$1"
    local host_id="$2"
    local new_ip="$3"

    log "Updating proxy host ${host_id} → forward to ${new_ip}..."

    # First, get the full current configuration to preserve all existing settings
    local current_config
    current_config=$(curl -s \
        -X GET "${NPM_API_URL}/nginx/proxy-hosts/${host_id}" \
        -H "Authorization: Bearer ${token}" \
        --connect-timeout 10 \
        --max-time 15)

    # Build the update payload preserving existing config, only changing forward_host
    local update_payload
    update_payload=$(echo "${current_config}" | jq \
        --arg new_ip "${new_ip}" \
        '. + {"forward_host": $new_ip}')

    if [ "${DRY_RUN}" = "true" ]; then
        log_warning "[DRY RUN] Would send PUT to ${NPM_API_URL}/nginx/proxy-hosts/${host_id}"
        log_warning "[DRY RUN] Payload: ${update_payload}"
        log_success "[DRY RUN] NPM failover simulation complete — no changes made."
        return 0
    fi

    local response
    response=$(curl -s -w "\n%{http_code}" \
        -X PUT "${NPM_API_URL}/nginx/proxy-hosts/${host_id}" \
        -H "Authorization: Bearer ${token}" \
        -H "Content-Type: application/json" \
        -d "${update_payload}" \
        --connect-timeout 10 \
        --max-time 15)

    local http_code
    http_code=$(echo "${response}" | tail -n1)
    local body
    body=$(echo "${response}" | head -n-1)

    if [ "${http_code}" != "200" ]; then
        log_error "Failed to update proxy host (HTTP ${http_code})"
        log_error "Response: ${body}"
        return 1
    fi

    # Verify the change was applied
    local confirmed_host
    confirmed_host=$(echo "${body}" | jq -r '.forward_host // empty')
    if [ "${confirmed_host}" != "${new_ip}" ]; then
        log_error "NPM accepted the request but the forward_host is '${confirmed_host}', expected '${new_ip}'."
        return 1
    fi

    log_success "NPM proxy host updated successfully: ${NPM_PROXY_HOST_DOMAIN} → ${new_ip}"
}

# ==============================================================================
# 8. MAIN
# ==============================================================================
main() {
    echo ""
    echo "========================================================="
    echo "  Wordly.art — NPM Failover"
    echo "  Target IP  : ${TARGET_IP:-NOT SET}"
    echo "  NPM API    : ${NPM_API_URL:-NOT SET}"
    echo "  Domain     : ${NPM_PROXY_HOST_DOMAIN}"
    echo "  Dry Run    : ${DRY_RUN}"
    echo "========================================================="
    echo ""

    validate_config

    # Step 1: Authenticate
    local token
    token=$(npm_authenticate)

    # Step 2: Find proxy host ID and current IP
    local host_info
    host_info=$(npm_find_proxy_host "${token}")
    local host_id="${host_info%%|*}"
    local current_ip="${host_info##*|}"

    if [ "${current_ip}" = "${TARGET_IP}" ]; then
        log_warning "NPM already points to ${TARGET_IP}. No change needed."
        exit 0
    fi

    # Step 3: Update forward host
    npm_update_proxy_host "${token}" "${host_id}" "${TARGET_IP}"

    # Step 4: Notify
    if [ "${DRY_RUN}" = "false" ]; then
        local msg="🔀 *Wordly.art NPM Failover*
Domaine : \`${NPM_PROXY_HOST_DOMAIN}\`
Ancien serveur : \`${current_ip}\`
Nouveau serveur : \`${TARGET_IP}\`
Heure : $(date '+%Y-%m-%d %H:%M:%S')"
        send_telegram "${msg}"
        log_success "Telegram notification sent."
    fi

    echo ""
    log_success "========================================================="
    log_success "NPM Failover COMPLETE"
    log_success "  ${NPM_PROXY_HOST_DOMAIN} now routes to → ${TARGET_IP}"
    log_success "========================================================="
    echo ""
}

main "$@"
