#!/usr/bin/bash
# shellcheck disable=SC2034
dns_exoscale_info='Exoscale.com
Site: Exoscale.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_exoscale
Options:
 EXOSCALE_API_KEY API Key
 EXOSCALE_SECRET_KEY API Secret key
'

EXOSCALE_API="https://api-ch-gva-2.exoscale.com/v2"

########  Public functions  ########

# Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
# Used to add txt record
dns_exoscale_add() {
  fulldomain=$1
  txtvalue=$2

  _debug "Using Exoscale DNS v2 API"
  _debug fulldomain "$fulldomain"
  _debug txtvalue "$txtvalue"

  if ! _check_auth; then
    return 1
  fi

  root_domain_id=$(_get_root_domain_id "$fulldomain")
  if [ -z "$root_domain_id" ]; then
    _err "Unable to determine root domain ID for $fulldomain"
    return 1
  fi
  _debug root_domain_id "$root_domain_id"

  # Always get the subdomain part first
  sub_domain=$(_get_sub_domain "$fulldomain" "$root_domain_id")
  _debug sub_domain "$sub_domain"

  # Build the record name properly
  if [ -z "$sub_domain" ]; then
    record_name="_acme-challenge"
  else
    record_name="_acme-challenge.$sub_domain"
  fi

  payload=$(printf '{"name":"%s","type":"TXT","content":"%s","ttl":120}' "$record_name" "$txtvalue")
  _debug payload "$payload"

  response=$(_exoscale_rest POST "/dns-domain/${root_domain_id}/record" "$payload")
  if _contains "$response" "\"id\""; then
    _info "TXT record added successfully."
    return 0
  else
    _err "Error adding TXT record: $response"
    return 1
  fi
}

dns_exoscale_rm() {
  fulldomain=$1

  _debug "Using Exoscale DNS v2 API for removal"
  _debug fulldomain "$fulldomain"

  if ! _check_auth; then
    return 1
  fi

  root_domain_id=$(_get_root_domain_id "$fulldomain")
  if [ -z "$root_domain_id" ]; then
    _err "Unable to determine root domain ID for $fulldomain"
    return 1
  fi

  record_name="_acme-challenge"
  sub_domain=$(_get_sub_domain "$fulldomain" "$root_domain_id")
  if [ -n "$sub_domain" ]; then
    record_name="_acme-challenge.$sub_domain"
  fi

  record_id=$(_find_record_id "$root_domain_id" "$record_name")
  if [ -z "$record_id" ]; then
    _err "TXT record not found for deletion."
    return 1
  fi

  response=$(_exoscale_rest DELETE "/dns-domain/$root_domain_id/record/$record_id")
  if _contains "$response" "\"state\":\"success\""; then
    _info "TXT record deleted successfully."
    return 0
  else
    _err "Error deleting TXT record: $response"
    return 1
  fi
}

########  Private helpers  ########

_check_auth() {
  EXOSCALE_API_KEY="${EXOSCALE_API_KEY:-$(_readaccountconf_mutable EXOSCALE_API_KEY)}"
  EXOSCALE_SECRET_KEY="${EXOSCALE_SECRET_KEY:-$(_readaccountconf_mutable EXOSCALE_SECRET_KEY)}"
  if [ -z "$EXOSCALE_API_KEY" ] || [ -z "$EXOSCALE_SECRET_KEY" ]; then
    _err "EXOSCALE_API_KEY and EXOSCALE_SECRET_KEY must be set."
    return 1
  fi
  _saveaccountconf_mutable EXOSCALE_API_KEY "$EXOSCALE_API_KEY"
  _saveaccountconf_mutable EXOSCALE_SECRET_KEY "$EXOSCALE_SECRET_KEY"
  return 0
}

_get_root_domain_id() {
  domain=$1
  i=1
  while true; do
    candidate=$(printf "%s" "$domain" | cut -d . -f "${i}-100")
    [ -z "$candidate" ] && return 1
    _debug "Trying root domain candidate: $candidate"
    domains=$(_exoscale_rest GET "/dns-domain")
    # Extract from dns-domains array
    result=$(echo "$domains" | _egrep_o '"dns-domains":\[.*\]' | _egrep_o '\{"id":"[^"]*","created-at":"[^"]*","unicode-name":"[^"]*"\}' | while read -r item; do
      name=$(echo "$item" | _egrep_o '"unicode-name":"[^"]*"' | cut -d'"' -f4)
      id=$(echo "$item" | _egrep_o '"id":"[^"]*"' | cut -d'"' -f4)
      if [ "$name" = "$candidate" ]; then
        echo "$id"
        break
      fi
    done)
    if [ -n "$result" ]; then
      echo "$result"
      return 0
    fi
    i=$(_math "$i" + 1)
  done
}

_get_sub_domain() {
  fulldomain=$1
  root_id=$2
  root_info=$(_exoscale_rest GET "/dns-domain/$root_id")
  _debug root_info "$root_info"
  root_name=$(echo "$root_info" | _egrep_o "\"unicode-name\":\"[^\"]*\"" | cut -d\" -f4)
  sub=${fulldomain%%."$root_name"}

  if [ "$sub" = "_acme-challenge" ]; then
    echo ""
  else
    # Remove _acme-challenge. prefix to get the actual subdomain
    echo "${sub#_acme-challenge.}"
  fi
}

_find_record_id() {
  root_id=$1
  name=$2
  records=$(_exoscale_rest GET "/dns-domain/$root_id/record")

  # Convert search name to lowercase for case-insensitive matching
  name_lower=$(echo "$name" | tr '[:upper:]' '[:lower:]')

  echo "$records" | _egrep_o '\{[^}]*"name":"[^"]*"[^}]*\}' | while read -r record; do
    record_name=$(echo "$record" | _egrep_o '"name":"[^"]*"' | cut -d'"' -f4)
    record_name_lower=$(echo "$record_name" | tr '[:upper:]' '[:lower:]')
    if [ "$record_name_lower" = "$name_lower" ]; then
      echo "$record" | _egrep_o '"id":"[^"]*"' | _head_n 1 | cut -d'"' -f4
      break
    fi
  done
}

_exoscale_sign() {
  k=$1
  shift
  hex_key=$(printf %b "$k" | _hex_dump | tr -d ' ')
  printf %s "$@" | _hmac sha256 "$hex_key"
}

_exoscale_rest() {
  method=$1
  path=$2
  data=$3

  url="${EXOSCALE_API}${path}"
  expiration=$(_math "$(date +%s)" + 300) # 5m from now

  # Build the message with the actual body or empty line
  message=$(printf "%s %s\n%s\n\n\n%s" "$method" "/v2$path" "$data" "$expiration")
  signature=$(_exoscale_sign "$EXOSCALE_SECRET_KEY" "$message" | _base64)
  auth="EXO2-HMAC-SHA256 credential=${EXOSCALE_API_KEY},expires=${expiration},signature=${signature}"

  _debug "API request: $method $url"
  _debug "Signed message: [$message]"
  _debug "Authorization header: [$auth]"

  export _H1="Accept: application/json"
  export _H2="Authorization: ${auth}"

  if [ "$data" ] || [ "$method" = "DELETE" ]; then
    export _H3="Content-Type: application/json"
    _debug data "$data"
    response="$(_post "$data" "$url" "" "$method")"
  else
    response="$(_get "$url" "" "" "$method")"
  fi

  # shellcheck disable=SC2181
  if [ "$?" -ne 0 ]; then
    _err "error $url"
    return 1
  fi
  _debug2 response "$response"
  echo "$response"
  return 0
}
