#!/bin/bash
echo "#############################################################"
echo "#                                                           "
echo "#  DNS Setup for Changemaker.lite Services                   "
echo "#                                                           "
echo "#  This script will ADD DNS records for your services.       "
echo "#  Existing DNS records will NOT be deleted.                 "
echo "#                                                           "
echo "#############################################################"
echo ""
echo "-------------------------------------------------------------"
echo "Cloudflare Credentials Required"
echo "Please ensure your .env file contains the following variables:"
echo "  CF_API_TOKEN=your_cloudflare_api_token"
echo "  CF_ZONE_ID=your_cloudflare_zone_id"
echo "  CF_TUNNEL_ID=your_cloudflared_tunnel_id"
echo "  CF_DOMAIN=yourdomain.com"
echo ""
echo "You can find these values in your Cloudflare dashboard:"
echo "  - API Token: https://dash.cloudflare.com/profile/api-tokens (Create a token with Zone:DNS:Edit and Access:Apps:Edit permissions for your domain)"
echo "  - Zone ID: On your domain's overview page"
echo "  - Tunnel ID: In the Zero Trust dashboard under Access > Tunnels"
echo "  - Domain: The domain you want to use for your services"
echo ""
echo "-------------------------------------------------------------"
echo ""
read -p "Type 'y' to continue or any other key to abort: " consent
if [[ "$consent" != "y" && "$consent" != "Y" ]]; then
  echo "Aborted by user."
  exit 1
fi

# Source environment variables from the .env file in the same directory
ENV_FILE="$(dirname "$0")/.env"
if [ -f "$ENV_FILE" ]; then
  export $(grep -v '^#' "$ENV_FILE" | xargs)
else
  echo "Error: .env file not found at $ENV_FILE"
  exit 1
fi

# Check if required Cloudflare variables are set
if [ -z "$CF_API_TOKEN" ] || [ -z "$CF_ZONE_ID" ] || [ -z "$CF_TUNNEL_ID" ] || [ -z "$CF_DOMAIN" ]; then
  echo "Error: One or more required Cloudflare environment variables (CF_API_TOKEN, CF_ZONE_ID, CF_TUNNEL_ID, CF_DOMAIN) are not set in $ENV_FILE."
  exit 1
fi

# Check if jq is installed
if ! command -v jq &> /dev/null; then
    echo "Error: jq is required but not installed. Please install jq to continue."
    echo "On Debian/Ubuntu: sudo apt-get install jq"
    echo "On RHEL/CentOS: sudo yum install jq"
    exit 1
fi

# Array of subdomains that need DNS records - updated to match our active services
SUBDOMAINS=(
  "dashboard"
  "code"
  "listmonk"
  "docs"
  "n8n"
  "db"
  "git"
)

# Function to check if DNS record already exists
record_exists() {
  local subdomain=$1
  local records=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records?name=$subdomain.$CF_DOMAIN" \
    -H "Authorization: Bearer $CF_API_TOKEN" \
    -H "Content-Type: application/json")
  
  local count=$(echo $records | jq -r '.result | length')
  [ "$count" -gt 0 ]
}

# Add CNAME records for each subdomain (only if they don't exist)
echo "Adding DNS records for services..."

for subdomain in "${SUBDOMAINS[@]}"; do
  if record_exists "$subdomain"; then
    echo "DNS record for $subdomain.$CF_DOMAIN already exists, skipping..."
  else
    echo "Adding CNAME record for $subdomain.$CF_DOMAIN..."
    
    response=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records" \
      -H "Authorization: Bearer $CF_API_TOKEN" \
      -H "Content-Type: application/json" \
      --data "{
        \"type\": \"CNAME\",
        \"name\": \"$subdomain\",
        \"content\": \"$CF_TUNNEL_ID.cfargotunnel.com\",
        \"ttl\": 1,
        \"proxied\": true
      }")
    
    success=$(echo $response | jq -r '.success')
    if [ "$success" == "true" ]; then
      echo "✓ Successfully added CNAME record for $subdomain.$CF_DOMAIN"
    else
      echo "✗ Failed to add CNAME record for $subdomain.$CF_DOMAIN"
      echo "Error: $(echo $response | jq -r '.errors[0].message')"
    fi
  fi
done

# Add root domain record if it doesn't exist
if record_exists "@"; then
  echo "Root domain DNS record already exists, skipping..."
else
  echo "Adding root domain CNAME record..."
  response=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records" \
    -H "Authorization: Bearer $CF_API_TOKEN" \
    -H "Content-Type: application/json" \
    --data "{
      \"type\": \"CNAME\",
      \"name\": \"@\",
      \"content\": \"$CF_TUNNEL_ID.cfargotunnel.com\",
      \"ttl\": 1,
      \"proxied\": true
    }")
  
  success=$(echo $response | jq -r '.success')
  if [ "$success" == "true" ]; then
    echo "✓ Successfully added root domain CNAME record"
  else
    echo "✗ Failed to add root domain CNAME record"
    echo "Error: $(echo $response | jq -r '.errors[0].message')"
  fi
fi

echo ""
echo "DNS records setup complete!"
echo ""

# Prompt for admin email for secured services
echo "-------------------------------------------------------------"
echo "Setting up Cloudflare Access Protection"
echo "-------------------------------------------------------------"
echo ""
echo "The following services will be protected with authentication:"
echo "  - dashboard.$CF_DOMAIN"
echo "  - code.$CF_DOMAIN"
echo ""
echo "Please enter the admin email address that should have access:"
read ADMIN_EMAIL

# Validate email format
if [[ ! "$ADMIN_EMAIL" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
  echo "Error: Invalid email format. Please provide a valid email address."
  exit 1
fi

# Services that require authentication - updated for our use case
PROTECTED_SERVICES=("dashboard" "code")

# Services that should have bypass policies (public access) - updated for our use case
BYPASS_SERVICES=("listmonk" "docs" "n8n" "db" "git")

# Function to create access application with email authentication
create_protected_app() {
  local service=$1
  echo "Setting up authentication for $service.$CF_DOMAIN..."
  
  app_response=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/access/apps" \
    -H "Authorization: Bearer $CF_API_TOKEN" \
    -H "Content-Type: application/json" \
    --data "{
      \"name\": \"$service $CF_DOMAIN\",
      \"domain\": \"$service.$CF_DOMAIN\",
      \"type\": \"self_hosted\",
      \"session_duration\": \"24h\",
      \"app_launcher_visible\": true,
      \"skip_interstitial\": true
    }")

  app_id=$(echo $app_response | jq -r '.result.id')

  if [ -z "$app_id" ] || [ "$app_id" == "null" ]; then
    echo "✗ Error creating access application for $service"
    return 1
  fi

  echo "✓ Created access application for $service (ID: $app_id)"
  
  # Create authentication policy
  policy_response=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/access/apps/$app_id/policies" \
    -H "Authorization: Bearer $CF_API_TOKEN" \
    -H "Content-Type: application/json" \
    --data "{
      \"name\": \"Admin Access\",
      \"decision\": \"allow\",
      \"include\": [{
        \"email\": {
          \"email\": \"$ADMIN_EMAIL\"
        }
      }],
      \"require\": [],
      \"exclude\": []
    }")
  
  policy_success=$(echo $policy_response | jq -r '.success')
  
  if [ "$policy_success" == "true" ]; then
    echo "✓ Created authentication policy for $service"
  else
    echo "✗ Failed to create authentication policy for $service"
  fi
}

# Function to create bypass application (public access)
create_bypass_app() {
  local service=$1
  echo "Setting up public access for $service.$CF_DOMAIN..."
  
  app_response=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/access/apps" \
    -H "Authorization: Bearer $CF_API_TOKEN" \
    -H "Content-Type: application/json" \
    --data "{
      \"name\": \"$service $CF_DOMAIN\",
      \"domain\": \"$service.$CF_DOMAIN\",
      \"type\": \"self_hosted\",
      \"session_duration\": \"24h\",
      \"app_launcher_visible\": false,
      \"skip_interstitial\": true
    }")

  app_id=$(echo $app_response | jq -r '.result.id')

  if [ -z "$app_id" ] || [ "$app_id" == "null" ]; then
    echo "✗ Error creating access application for $service"
    return 1
  fi

  echo "✓ Created access application for $service (ID: $app_id)"
  
  # Create bypass policy
  policy_response=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/access/apps/$app_id/policies" \
    -H "Authorization: Bearer $CF_API_TOKEN" \
    -H "Content-Type: application/json" \
    --data "{
      \"name\": \"Public Access\",
      \"decision\": \"bypass\",
      \"include\": [{
        \"everyone\": {}
      }],
      \"require\": [],
      \"exclude\": []
    }")
  
  policy_success=$(echo $policy_response | jq -r '.success')
  
  if [ "$policy_success" == "true" ]; then
    echo "✓ Created public access policy for $service"
  else
    echo "✗ Failed to create public access policy for $service"
  fi
}

echo "Creating Cloudflare Access applications..."
echo ""

# Create protected applications
for service in "${PROTECTED_SERVICES[@]}"; do
  create_protected_app "$service"
  echo ""
done

# Create bypass applications for public services
for service in "${BYPASS_SERVICES[@]}"; do
  create_bypass_app "$service"
  echo ""
done

echo "-------------------------------------------------------------"
echo "Setup Complete!"
echo "-------------------------------------------------------------"
echo ""
echo "Protected services (require authentication with $ADMIN_EMAIL):"
for service in "${PROTECTED_SERVICES[@]}"; do
  echo "  - https://$service.$CF_DOMAIN"
done
echo ""
echo "Public services (no authentication required):"
for service in "${BYPASS_SERVICES[@]}"; do
  echo "  - https://$service.$CF_DOMAIN"
done
echo ""
echo "All services should be accessible through your Cloudflare tunnel."
