#!/usr/bin/env bash
# Configure Cloudflare Access policies with allowed email addresses
# Usage: ./configure-access-policies.sh [email1] [email2] [email3] ...

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TUNNELS_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"

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

log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[✓]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[⚠]${NC} $1"; }
log_error() { echo -e "${RED}[✗]${NC} $1"; }

# Load .env
if [ -f "$TUNNELS_DIR/../../.env" ]; then
    source "$TUNNELS_DIR/../../.env" 2>/dev/null || true
fi

if [[ -z "${CLOUDFLARE_ACCOUNT_ID:-}" ]] || [[ -z "${CLOUDFLARE_API_KEY:-}" ]] || [[ -z "${CLOUDFLARE_EMAIL:-}" ]]; then
    log_error "Cloudflare credentials not found in .env"
    exit 1
fi

# Get email addresses from command line or prompt
ALLOWED_EMAILS=("$@")

if [ ${#ALLOWED_EMAILS[@]} -eq 0 ]; then
    log_info "Enter allowed email addresses (one per line, empty line to finish):"
    while IFS= read -r email; do
        [[ -z "$email" ]] && break
        [[ "$email" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]] || {
            log_warn "Invalid email format: $email (skipping)"
            continue
        }
        ALLOWED_EMAILS+=("$email")
    done
fi

if [ ${#ALLOWED_EMAILS[@]} -eq 0 ]; then
    log_error "No email addresses provided"
    exit 1
fi

log_info "Allowed emails: ${ALLOWED_EMAILS[*]}"
echo ""

# Function to make API request
cf_api_request() {
    local method="$1"
    local endpoint="$2"
    local data="${3:-}"
    
    local url="https://api.cloudflare.com/client/v4${endpoint}"
    local temp_file=$(mktemp)
    local http_code
    
    if [[ -n "$data" ]]; then
        http_code=$(curl -s -o "$temp_file" -w "%{http_code}" \
            -X "$method" "$url" \
            -H "X-Auth-Email: ${CLOUDFLARE_EMAIL}" \
            -H "X-Auth-Key: ${CLOUDFLARE_API_KEY}" \
            -H "Content-Type: application/json" \
            -d "$data" 2>/dev/null)
    else
        http_code=$(curl -s -o "$temp_file" -w "%{http_code}" \
            -X "$method" "$url" \
            -H "X-Auth-Email: ${CLOUDFLARE_EMAIL}" \
            -H "X-Auth-Key: ${CLOUDFLARE_API_KEY}" \
            -H "Content-Type: application/json" 2>/dev/null)
    fi
    
    local response=$(cat "$temp_file" 2>/dev/null || echo "")
    rm -f "$temp_file"
    
    if [[ "$http_code" != "200" ]] && [[ "$http_code" != "201" ]]; then
        log_error "API request failed (HTTP $http_code)"
        echo "$response" | jq -r '.errors[0].message // "Unknown error"' 2>/dev/null || echo "$response"
        return 1
    fi
    
    echo "$response"
}

# Get Access applications
log_info "Fetching Access applications..."
APPS_RESPONSE=$(cf_api_request "GET" "/accounts/${CLOUDFLARE_ACCOUNT_ID}/access/apps" 2>&1)

declare -A APP_IDS=()
for hostname in ml110-01.d-bis.org r630-01.d-bis.org r630-02.d-bis.org; do
    app_id=$(echo "$APPS_RESPONSE" | jq -r ".result[]? | select(.domain? == \"${hostname}\") | .id" 2>/dev/null || echo "")
    if [[ -n "$app_id" ]] && [[ "$app_id" != "null" ]] && [[ "$app_id" != "" ]]; then
        APP_IDS["$hostname"]="$app_id"
        log_success "Found app for $hostname: $app_id"
    else
        log_warn "No app found for $hostname"
    fi
done

if [ ${#APP_IDS[@]} -eq 0 ]; then
    log_error "No Access applications found"
    exit 1
fi

echo ""

# Build email include array
EMAIL_INCLUDES=$(printf '%s\n' "${ALLOWED_EMAILS[@]}" | jq -R . | jq -s . | jq 'map({email: {email: .}})')

# Configure policy for each app
for hostname in "${!APP_IDS[@]}"; do
    app_id="${APP_IDS[$hostname]}"
    
    log_info "Configuring policy for $hostname..."
    
    # Get existing policies
    POLICIES_RESPONSE=$(cf_api_request "GET" "/accounts/${CLOUDFLARE_ACCOUNT_ID}/access/apps/${app_id}/policies" 2>&1)
    EXISTING_POLICY_ID=$(echo "$POLICIES_RESPONSE" | jq -r '.result[] | select(.name == "Allow Team Access") | .id' 2>/dev/null || echo "")
    
    # Build policy data
    POLICY_DATA=$(jq -n \
        --argjson emails "$EMAIL_INCLUDES" \
        '{
            name: "Allow Team Access",
            decision: "allow",
            include: $emails,
            require: [
                {
                    email: {}
                }
            ]
        }')
    
    if [[ -n "$EXISTING_POLICY_ID" ]] && [[ "$EXISTING_POLICY_ID" != "null" ]]; then
        # Update existing policy
        log_info "  Updating existing policy..."
        response=$(cf_api_request "PUT" "/accounts/${CLOUDFLARE_ACCOUNT_ID}/access/apps/${app_id}/policies/${EXISTING_POLICY_ID}" "$POLICY_DATA" 2>&1)
    else
        # Create new policy
        log_info "  Creating new policy..."
        response=$(cf_api_request "POST" "/accounts/${CLOUDFLARE_ACCOUNT_ID}/access/apps/${app_id}/policies" "$POLICY_DATA" 2>&1)
    fi
    
    if echo "$response" | jq -e '.success' >/dev/null 2>&1; then
        log_success "  ✓ Policy configured for $hostname"
    else
        log_error "  ✗ Failed to configure policy for $hostname"
        echo "$response" | jq -r '.errors[0].message // "Unknown error"' 2>/dev/null
    fi
    
    echo ""
done

log_success "=== Access Policies Configured ==="
log_info "Allowed emails:"
for email in "${ALLOWED_EMAILS[@]}"; do
    echo "  - $email"
done
echo ""
log_info "These emails can now access:"
for hostname in "${!APP_IDS[@]}"; do
    echo "  - https://$hostname"
done

