#!/bin/bash
set -euo pipefail

# Cloudflare Tunnel Configuration Script

# Load environment variables from .env if it exists
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if [ -f "${SCRIPT_DIR}/../.env" ]; then
    set -a
    source <(grep -v '^#' "${SCRIPT_DIR}/../.env" | grep -v '^$' | sed 's/^/export /')
    set +a
fi

CLOUDFLARE_API_TOKEN="${CLOUDFLARE_API_TOKEN:-}"
CLOUDFLARE_API_KEY="${CLOUDFLARE_API_KEY:-}"
CLOUDFLARE_EMAIL="${CLOUDFLARE_EMAIL:-}"
ZONE_ID="${CLOUDFLARE_ZONE_ID:-${ZONE_ID:-}}"
ACCOUNT_ID="${CLOUDFLARE_ACCOUNT_ID:-${ACCOUNT_ID:-}}"

log() {
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*" >&2
}

error() {
    log "ERROR: $*"
    exit 1
}

check_prerequisites() {
    # Check authentication method
    if [ -z "${CLOUDFLARE_API_TOKEN}" ] && [ -z "${CLOUDFLARE_API_KEY}" ]; then
        error "Either CLOUDFLARE_API_TOKEN or CLOUDFLARE_API_KEY must be set"
    fi
    
    if [ -z "${CLOUDFLARE_API_TOKEN}" ] && [ -z "${CLOUDFLARE_EMAIL}" ]; then
        error "If using CLOUDFLARE_API_KEY, CLOUDFLARE_EMAIL must also be set"
    fi
    
    if [ -z "${ACCOUNT_ID}" ]; then
        warn "ACCOUNT_ID not set, attempting to get from API..."
        get_account_id
    fi
    
    if ! command -v cloudflared &> /dev/null; then
        error "cloudflared is not installed. Install it first."
    fi
}

get_account_id() {
    if [ -n "${CLOUDFLARE_API_TOKEN}" ]; then
        ACCOUNT_ID=$(curl -s -X GET \
            -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
            -H "Content-Type: application/json" \
            "https://api.cloudflare.com/client/v4/accounts" | \
            jq -r '.result[0].id')
    elif [ -n "${CLOUDFLARE_API_KEY}" ] && [ -n "${CLOUDFLARE_EMAIL}" ]; then
        ACCOUNT_ID=$(curl -s -X GET \
            -H "X-Auth-Email: ${CLOUDFLARE_EMAIL}" \
            -H "X-Auth-Key: ${CLOUDFLARE_API_KEY}" \
            -H "Content-Type: application/json" \
            "https://api.cloudflare.com/client/v4/accounts" | \
            jq -r '.result[0].id')
    fi
    
    if [ -n "${ACCOUNT_ID}" ] && [ "${ACCOUNT_ID}" != "null" ]; then
        log "Account ID: ${ACCOUNT_ID}"
        export CLOUDFLARE_ACCOUNT_ID="${ACCOUNT_ID}"
    else
        error "Failed to get Account ID"
    fi
}

create_tunnel() {
    local tunnel_name=$1
    
    log "Creating Cloudflare tunnel: ${tunnel_name}"
    
    # Create tunnel via API
    local auth_header
    if [ -n "${CLOUDFLARE_API_TOKEN}" ]; then
        TUNNEL_ID=$(curl -s -X POST \
            -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
            -H "Content-Type: application/json" \
            "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/cfd_tunnel" \
            -d "{\"name\":\"${tunnel_name}\",\"config_src\":\"local\"}" \
            | jq -r '.result.id')
    else
        TUNNEL_ID=$(curl -s -X POST \
            -H "X-Auth-Email: ${CLOUDFLARE_EMAIL}" \
            -H "X-Auth-Key: ${CLOUDFLARE_API_KEY}" \
            -H "Content-Type: application/json" \
            "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/cfd_tunnel" \
            -d "{\"name\":\"${tunnel_name}\",\"config_src\":\"local\"}" \
            | jq -r '.result.id')
    fi
    
    if [ -z "${TUNNEL_ID}" ] || [ "${TUNNEL_ID}" = "null" ]; then
        error "Failed to create tunnel ${tunnel_name}"
    fi
    
    log "Tunnel created with ID: ${TUNNEL_ID}"
    echo "${TUNNEL_ID}"
}

get_tunnel_token() {
    local tunnel_id=$1
    
    log "Getting tunnel token for ${tunnel_id}..."
    
    TOKEN=$(curl -s -X GET \
        -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
        "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/cfd_tunnel/${tunnel_id}/token" \
        | jq -r '.result.token')
    
    if [ -z "${TOKEN}" ] || [ "${TOKEN}" = "null" ]; then
        error "Failed to get tunnel token"
    fi
    
    echo "${TOKEN}"
}

configure_dns() {
    local hostname=$1
    local tunnel_id=$2
    
    log "Configuring DNS for ${hostname}..."
    
    # Create CNAME record
    curl -s -X POST \
        -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
        -H "Content-Type: application/json" \
        "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records" \
        -d "{
            \"type\": \"CNAME\",
            \"name\": \"${hostname}\",
            \"content\": \"${tunnel_id}.cfargotunnel.com\",
            \"ttl\": 1,
            \"proxied\": true
        }" > /dev/null
    
    log "DNS record created for ${hostname}"
}

setup_control_plane_tunnel() {
    log "Setting up control plane tunnel..."
    
    TUNNEL_ID=$(create_tunnel "control-plane-tunnel")
    TUNNEL_TOKEN=$(get_tunnel_token "${TUNNEL_ID}")
    
    log "Control plane tunnel token: ${TUNNEL_TOKEN}"
    log "Save this token securely and use it when running cloudflared on control plane nodes"
    
    # Configure DNS for control plane services
    configure_dns "portal" "${TUNNEL_ID}"
    configure_dns "rancher" "${TUNNEL_ID}"
    configure_dns "argocd" "${TUNNEL_ID}"
    configure_dns "grafana" "${TUNNEL_ID}"
    configure_dns "vault" "${TUNNEL_ID}"
    configure_dns "keycloak" "${TUNNEL_ID}"
}

setup_proxmox_tunnels() {
    local sites=("site-1" "site-2" "site-3")
    
    for site in "${sites[@]}"; do
        log "Setting up tunnel for ${site}..."
        
        TUNNEL_ID=$(create_tunnel "proxmox-${site}-tunnel")
        TUNNEL_TOKEN=$(get_tunnel_token "${TUNNEL_ID}")
        
        log "${site} tunnel token: ${TUNNEL_TOKEN}"
        log "Save this token and use it when running setup-proxmox-agents.sh on ${site} nodes"
    done
}

main() {
    log "Starting Cloudflare tunnel configuration..."
    
    check_prerequisites
    setup_control_plane_tunnel
    setup_proxmox_tunnels
    
    log ""
    log "Cloudflare tunnel configuration completed!"
    log ""
    log "Next steps:"
    log "1. Save all tunnel tokens securely"
    log "2. Use tokens when running cloudflared on respective nodes"
    log "3. Verify DNS records are created correctly"
    log "4. Test tunnel connectivity"
}

main "$@"

