# This task file ensures that a Cloudflare "Dynamic Redirect Rule" exists
# which redirects www.example.com → https://example.com{uri} with 301.

# Required vars to pass in:
#   www_fqdn:   "www.example.com"
#   apex_url:   "https://example.com"
#   CLOUDFLARE_API_TOKEN

- name: "Derive zone and apex from www_fqdn"
  set_fact:
    cf_zone_name: "{{ www_fqdn | to_zone }}"                       # e.g. "cymais.cloud"
    domain_apex: "{{ www_fqdn | regex_replace('^www\\.', '') }}"   # e.g. "academy.cymais.cloud"

- name: "Cloudflare: Lookup zone id for {{ cf_zone_name }}"
  ansible.builtin.uri:
    url: "https://api.cloudflare.com/client/v4/zones?name={{ cf_zone_name }}"
    method: GET
    headers:
      Authorization: "Bearer {{ CLOUDFLARE_API_TOKEN }}"
      Content-Type: "application/json"
    return_content: true
  register: cf_zone_lookup
  failed_when: >
    (cf_zone_lookup.status != 200) or
    (cf_zone_lookup.json.result | length) == 0

- name: "Set fact: zone_id"
  set_fact:
    cf_zone_id: "{{ (cf_zone_lookup.json.result | first).id }}"

- name: "Remove conflicting A/AAAA record for {{ www_fqdn }}"
  community.general.cloudflare_dns:
    api_token: "{{ CLOUDFLARE_API_TOKEN }}"
    zone: "{{ cf_zone_name }}"
    type: "A"
    name: "{{ www_fqdn }}"
    state: absent
  ignore_errors: true

- name: "Cloudflare DNS: ensure {{ www_fqdn }} is proxied (CNAME)"
  community.general.cloudflare_dns:
    api_token: "{{ CLOUDFLARE_API_TOKEN }}"
    zone: "{{ cf_zone_name }}"
    type: "CNAME"
    name: "{{ www_fqdn }}"
    value: "{{ domain_apex }}"
    proxied: true
    ttl: 1
    state: present
    
# 1) Fetch existing redirect rulesets
- name: "Cloudflare Rulesets: list dynamic redirect rulesets"
  ansible.builtin.uri:
    url: "https://api.cloudflare.com/client/v4/zones/{{ cf_zone_id }}/rulesets?phase=http_request_dynamic_redirect"
    method: GET
    headers:
      Authorization: "Bearer {{ CLOUDFLARE_API_TOKEN }}"
      Content-Type: "application/json"
    return_content: true
  register: cf_rulesets

- name: "Pick existing custom ruleset (if any)"
  set_fact:
    cf_redirect_ruleset: >-
      {{
        (cf_rulesets.json.result | default([]))
        | selectattr('kind','equalto','zone')
        | list
        | first
      }}
    cf_redirect_ruleset_id: "{{ (cf_redirect_ruleset.id | default('')) }}"

# Desired redirect rule object
- name: "Build desired redirect rule object"
  set_fact:
    desired_redirect_rule:
      ref: "redirect_www_to_apex"
      description: "Redirect www → apex (301)"
      expression: "http.host eq \"{{ www_fqdn }}\""
      action: "redirect"
      action_parameters:
        from_value:
          target_url:
            expression: "\"{{ apex_url }}\" + http.request.uri.path + (len(http.request.uri.query) > 0 ? (\"?\" + http.request.uri.query) : \"\")"
          status_code: 301
          preserve_query_string: true

# 2) Update existing ruleset (PUT)
- name: "Update existing dynamic redirect ruleset (PUT)"
  when: cf_redirect_ruleset_id | length > 0
  vars:
    existing_rules: "{{ cf_redirect_ruleset.rules | default([]) }}"
    merged_rules: >-
      {{
        (
          (existing_rules | rejectattr('ref','equalto', desired_redirect_rule.ref) | list)
          + [ desired_redirect_rule ]
        )
      }}
  ansible.builtin.uri:
    url: "https://api.cloudflare.com/client/v4/zones/{{ cf_zone_id }}/rulesets/{{ cf_redirect_ruleset_id }}"
    method: PUT
    headers:
      Authorization: "Bearer {{ CLOUDFLARE_API_TOKEN }}"
      Content-Type: "application/json"
    status_code: 200
    body_format: json
    body:
      name: "{{ cf_redirect_ruleset.name | default('www-to-apex') }}"
      kind: "zone"
      phase: "http_request_dynamic_redirect"
      rules: "{{ merged_rules }}"
  register: cf_ruleset_update
  changed_when: cf_ruleset_update.status in [200]

# 3) Create new ruleset (POST)
- name: "Create dynamic redirect ruleset (POST)"
  when: cf_redirect_ruleset_id | length == 0
  ansible.builtin.uri:
    url: "https://api.cloudflare.com/client/v4/zones/{{ cf_zone_id }}/rulesets"
    method: POST
    headers:
      Authorization: "Bearer {{ CLOUDFLARE_API_TOKEN }}"
      Content-Type: "application/json"
    status_code: 200
    body_format: json
    body:
      name: "www-to-apex"
      kind: "zone"
      phase: "http_request_dynamic_redirect"
      rules:
        - "{{ desired_redirect_rule }}"
  register: cf_ruleset_create
  changed_when: cf_ruleset_create.status in [200]
