name: Sync Cloudflare bulk redirects

on:
  workflow_dispatch:
  push:
    branches: [main]
    paths:
      - "dns/bulk-redirects.json"
      - ".github/workflows/sync-bulk-redirects.yml"

permissions:
  contents: read

jobs:
  sync:
    runs-on: ubuntu-latest
    env:
      CLOUDFLARE_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN || secrets.CLOUDFLARE_DNS_TOKEN || secrets.CLOUDFLARE_API_TOKEN }}
    steps:
      - name: Skip if token missing
        if: env.CLOUDFLARE_TOKEN == ''
        run: echo "CLOUDFLARE_TOKEN not set; skipping sync."

      - name: Checkout
        if: env.CLOUDFLARE_TOKEN != ''
        uses: actions/checkout@v4

      - name: Sync bulk redirects list and rule
        if: env.CLOUDFLARE_TOKEN != ''
        run: |
          set -euo pipefail

          account_id=$(jq -r '.account_id // empty' dns/bulk-redirects.json)
          list_name=$(jq -r '.list_name // empty' dns/bulk-redirects.json)
          description=$(jq -r '.description // "CultRoll bulk redirects"' dns/bulk-redirects.json)
          if [ -z "$account_id" ] || [ -z "$list_name" ]; then
            echo "account_id and list_name are required in dns/bulk-redirects.json" >&2
            exit 1
          fi

          items_payload=$(jq -c '[.items[]? | {redirect: .}]' dns/bulk-redirects.json)
          list_ref=$(printf '%s' "$list_name" | tr '.-' '_' | tr -cd 'A-Za-z0-9_')
          rule_ref="enable_${list_ref}"

          lists_resp=$(curl -sS \
            -H "Authorization: Bearer $CLOUDFLARE_TOKEN" \
            "https://api.cloudflare.com/client/v4/accounts/${account_id}/rules/lists")
          list_id=$(echo "$lists_resp" | jq -r --arg NAME "$list_name" '.result[]? | select(.name == $NAME) | .id')

          if [ -z "$list_id" ]; then
            create_list_payload=$(jq -nc \
              --arg name "$list_name" \
              --arg description "$description" \
              '{name: $name, description: $description, kind: "redirect"}')
            create_list_resp=$(curl -sS -X POST \
              -H "Authorization: Bearer $CLOUDFLARE_TOKEN" \
              -H "Content-Type: application/json" \
              "https://api.cloudflare.com/client/v4/accounts/${account_id}/rules/lists" \
              --data "$create_list_payload")
            list_id=$(echo "$create_list_resp" | jq -r '.result.id // empty')
            if [ -z "$list_id" ]; then
              echo "Failed to create redirect list" >&2
              echo "$create_list_resp" | jq || true
              exit 1
            fi
          fi

          update_resp=$(curl -sS -X PUT \
            -H "Authorization: Bearer $CLOUDFLARE_TOKEN" \
            -H "Content-Type: application/json" \
            "https://api.cloudflare.com/client/v4/accounts/${account_id}/rules/lists/${list_id}/items" \
            --data "$items_payload")
          echo "$update_resp" | jq || true

          operation_id=$(echo "$update_resp" | jq -r '.result.operation_id // empty')
          if [ -n "$operation_id" ]; then
            for _ in $(seq 1 20); do
              op_resp=$(curl -sS \
                -H "Authorization: Bearer $CLOUDFLARE_TOKEN" \
                "https://api.cloudflare.com/client/v4/accounts/${account_id}/rules/lists/bulk_operations/${operation_id}")
              op_status=$(echo "$op_resp" | jq -r '.result.status // empty')
              if [ "$op_status" = "completed" ]; then
                break
              fi
              if [ "$op_status" = "failed" ]; then
                echo "Bulk redirect list update failed" >&2
                echo "$op_resp" | jq || true
                exit 1
              fi
              sleep 3
            done
          fi

          rule_json=$(jq -nc \
            --arg ref "$rule_ref" \
            --arg list "$list_name" \
            --arg desc "$description" \
            '{
              ref: $ref,
              expression: ("http.request.full_uri in $" + $list),
              description: $desc,
              action: "redirect",
              action_parameters: {
                from_list: {
                  name: $list,
                  key: "http.request.full_uri"
                }
              }
            }')

          entrypoint_resp=$(curl -sS \
            -H "Authorization: Bearer $CLOUDFLARE_TOKEN" \
            "https://api.cloudflare.com/client/v4/accounts/${account_id}/rulesets/phases/http_request_redirect/entrypoint")

          entrypoint_id=$(echo "$entrypoint_resp" | jq -r '.result.id // empty')
          if [ -z "$entrypoint_id" ]; then
            create_ruleset_payload=$(jq -nc \
              --arg desc "$description" \
              --argjson rule "$rule_json" \
              '{name: $desc, kind: "root", phase: "http_request_redirect", rules: [$rule]}')
            create_ruleset_resp=$(curl -sS -X POST \
              -H "Authorization: Bearer $CLOUDFLARE_TOKEN" \
              -H "Content-Type: application/json" \
              "https://api.cloudflare.com/client/v4/accounts/${account_id}/rulesets" \
              --data "$create_ruleset_payload")
            success=$(echo "$create_ruleset_resp" | jq -r '.success')
            if [ "$success" != "true" ]; then
              echo "Failed to create redirect ruleset" >&2
              echo "$create_ruleset_resp" | jq || true
              exit 1
            fi
            exit 0
          fi

          ruleset_name=$(echo "$entrypoint_resp" | jq -r '.result.name // "Account redirect ruleset"')
          updated_rules=$(echo "$entrypoint_resp" | jq \
            --argjson newRule "$rule_json" \
            '(.result.rules // []) as $rules
            | if any($rules[]?; .ref == $newRule.ref) then
                [ $rules[] | if .ref == $newRule.ref then $newRule else . end ]
              else
                $rules + [$newRule]
              end')

          update_ruleset_payload=$(jq -nc \
            --arg name "$ruleset_name" \
            --argjson rules "$updated_rules" \
            '{name: $name, kind: "root", phase: "http_request_redirect", rules: $rules}')

          update_ruleset_resp=$(curl -sS -X PUT \
            -H "Authorization: Bearer $CLOUDFLARE_TOKEN" \
            -H "Content-Type: application/json" \
            "https://api.cloudflare.com/client/v4/accounts/${account_id}/rulesets/${entrypoint_id}" \
            --data "$update_ruleset_payload")
          success=$(echo "$update_ruleset_resp" | jq -r '.success')
          if [ "$success" != "true" ]; then
            echo "Failed to update redirect ruleset" >&2
            echo "$update_ruleset_resp" | jq || true
            exit 1
          fi
