#!/usr/bin/env bash

#########################################################################################
#### hetzner-dns-manager.sh — Manage DNS zones and records via the Hetzner DNS API   ####
#### List zones, add/update/delete records, BIND export/import, audit, bulk ops      ####
#### Requires: bash 4+, curl, jq                                                     ####
####                                                                                 ####
#### Author: Phil Connor                                                             ####
#### Contact: contact@mylinux.work                                                   ####
#### License: MIT                                                                    ####
#### Version 1.01                                                                    ####
####                                                                                 ####
#### Usage:                                                                          ####
####   ./hetzner-dns-manager.sh --zones                                              ####
####                                                                                 ####
#### See --help for all options.                                                     ####
#########################################################################################

set -euo pipefail

# ── Colors (pre-initialized) ─────────────────────────────────────────
RED="" GREEN="" YELLOW="" BLUE="" CYAN="" BOLD="" DIM="" RESET=""

setup_colors() {
    if [[ "${COLOR:-auto}" == "never" ]]; then
        return
    fi
    if [[ "${COLOR:-auto}" == "always" ]] || [[ -t 1 ]]; then
        RED='\033[0;31m'
        GREEN='\033[0;32m'
        YELLOW='\033[0;33m'
        BLUE='\033[0;34m'
        CYAN='\033[0;36m'
        BOLD='\033[1m'
        DIM='\033[2m'
        RESET='\033[0m'
    fi
}

# ── Logging ───────────────────────────────────────────────────────────
log()     { echo -e "${BLUE}[INFO]${RESET} $*"; }
warn()    { echo -e "${YELLOW}[WARN]${RESET} $*" >&2; }
err()     { echo -e "${RED}[ERROR]${RESET} $*" >&2; }
verbose() { if [[ "$VERBOSE" == "true" ]]; then echo -e "${DIM}[DEBUG]${RESET} $*"; fi; }
die()     { err "$*"; exit 1; }

section_header() {
    echo ""
    echo -e "  ${BOLD}${CYAN}── $1 ──${RESET}"
    echo ""
}

field() {
    printf "  ${BOLD}%-22s${RESET} %s\n" "$1" "$2"
}

field_color() {
    printf "  ${BOLD}%-22s${RESET} %b\n" "$1" "$2"
}

elapsed() {
    local end_time
    end_time=$(date +%s)
    echo "$(( end_time - START_TIME ))s"
}

# ── Defaults ──────────────────────────────────────────────────────────
RUN_MODE=""
ZONE_NAME=""
ZONE_ID=""
RECORD_ID=""
RECORD_TYPE=""
RECORD_NAME=""
RECORD_VALUE=""
RECORD_TTL="3600"
CSV_FILE=""
OUTPUT_FORMAT="${HDM_FORMAT:-table}"
FORCE="false"
VERBOSE="${VERBOSE:-false}"
COLOR="${COLOR:-auto}"
IMPORT_FILE=""
EXPORT_FILE=""

# ── Credentials ───────────────────────────────────────────────────────
HETZNER_DNS_TOKEN="${HETZNER_DNS_TOKEN:-}"

# ── State ─────────────────────────────────────────────────────────────
SCRIPT_NAME="$(basename "$0")"
readonly SCRIPT_NAME
START_TIME=""
ACTION_OK=0
ACTION_FAIL=0

# ── API helpers ──────────────────────────────────────────────────────
hdns_api() {
    local method="$1" endpoint="$2"
    shift 2
    local attempt=0 max_attempts=3

    while (( attempt < max_attempts )); do
        local http_code
        http_code=$(curl -s -o /tmp/hdm_resp.json -w "%{http_code}" \
            -X "$method" \
            -H "Auth-API-Token: ${HETZNER_DNS_TOKEN}" \
            -H "Content-Type: application/json" \
            "https://dns.hetzner.com/api/v1${endpoint}" "$@")

        verbose "API ${method} ${endpoint} → HTTP ${http_code}"

        if [[ "$http_code" == "429" ]]; then
            ((attempt++)) || true
            local wait=$(( attempt * 5 ))
            warn "Rate limited — retrying in ${wait}s (attempt ${attempt}/${max_attempts})"
            sleep "$wait"
            continue
        fi

        if [[ "$http_code" =~ ^[45] ]]; then
            local errmsg
            errmsg=$(jq -r '.error.message // .message // empty' /tmp/hdm_resp.json 2>/dev/null)
            [[ -n "$errmsg" ]] && verbose "API error: ${errmsg}"
        fi

        cat /tmp/hdm_resp.json
        return 0
    done

    err "API request failed after ${max_attempts} attempts: ${method} ${endpoint}"
    return 1
}

hdns_api_raw() {
    local method="$1" endpoint="$2"
    shift 2

    curl -s \
        -X "$method" \
        -H "Auth-API-Token: ${HETZNER_DNS_TOKEN}" \
        "https://dns.hetzner.com/api/v1${endpoint}" "$@"
}

check_credentials() {
    [[ -z "$HETZNER_DNS_TOKEN" ]] && die "HETZNER_DNS_TOKEN not set"
}

check_deps() {
    command -v curl &>/dev/null || die "curl is required"
    command -v jq &>/dev/null || die "jq is required"
}

# ── Zone helpers ─────────────────────────────────────────────────────
resolve_zone_id() {
    local name="$1"
    local resp
    resp=$(hdns_api GET "/zones?name=${name}")
    local zid
    zid=$(echo "$resp" | jq -r '.zones[0].id // empty' 2>/dev/null)
    if [[ -z "$zid" ]]; then
        die "Zone not found: ${name}"
    fi
    echo "$zid"
}

# ══════════════════════════════════════════════════════════════════════
#                          ZONES
# ══════════════════════════════════════════════════════════════════════
do_zones() {
    local page=1 per_page=100 all_data="[]"

    while true; do
        local resp
        resp=$(hdns_api GET "/zones?page=${page}&per_page=${per_page}")
        local page_data
        page_data=$(echo "$resp" | jq '.zones // []' 2>/dev/null)
        local page_count
        page_count=$(echo "$page_data" | jq 'length' 2>/dev/null || echo 0)
        [[ "$page_count" -eq 0 ]] && break
        all_data=$(echo -e "${all_data}\n${page_data}" | jq -s 'add' 2>/dev/null)
        (( page_count < per_page )) && break
        ((page++)) || true
    done

    local total
    total=$(echo "$all_data" | jq 'length' 2>/dev/null || echo 0)
    [[ "$total" -eq 0 ]] && die "No zones found"

    case "$OUTPUT_FORMAT" in
        json)
            echo "$all_data" | jq '.'
            ;;
        prometheus)
            cat <<EOF
# HELP hetzner_dns_zones_total Total DNS zones
# TYPE hetzner_dns_zones_total gauge
hetzner_dns_zones_total ${total}
EOF
            ;;
        *)
            section_header "DNS Zones"

            printf "  ${BOLD}%-34s %-18s %-10s %-8s %-8s${RESET}\n" \
                "ZONE_ID" "NAME" "STATUS" "RECORDS" "TTL"
            printf "  %s\n" "$(printf '%.0s─' {1..80})"

            echo "$all_data" | jq -r \
                '.[] | "\(.id)\t\(.name // "unknown")\t\(.status // "—")\t\(.records_count // 0)\t\(.ttl // 0)"' \
                2>/dev/null \
                | while IFS=$'\t' read -r zid name status rcount ttl; do
                    printf "  %-34s %-18s %-10s %-8s %-8s\n" \
                        "${zid:0:32}" "${name:0:16}" "$status" "$rcount" "$ttl"
                done

            echo ""
            field "Zones:" "$total"
            ;;
    esac
}

# ══════════════════════════════════════════════════════════════════════
#                          RECORDS
# ══════════════════════════════════════════════════════════════════════
do_records() {
    [[ -z "$ZONE_NAME" ]] && die "Specify --zone DOMAIN"

    local zid
    zid=$(resolve_zone_id "$ZONE_NAME")

    local resp
    resp=$(hdns_api GET "/records?zone_id=${zid}")
    local records
    records=$(echo "$resp" | jq '.records // []' 2>/dev/null)
    local total
    total=$(echo "$records" | jq 'length' 2>/dev/null || echo 0)

    case "$OUTPUT_FORMAT" in
        json)
            echo "$records" | jq '.'
            ;;
        prometheus)
            cat <<EOF
# HELP hetzner_dns_records_total Total DNS records
# TYPE hetzner_dns_records_total gauge
hetzner_dns_records_total ${total}
# HELP hetzner_dns_zone_records DNS records per zone
# TYPE hetzner_dns_zone_records gauge
hetzner_dns_zone_records{zone="${ZONE_NAME}"} ${total}
EOF
            ;;
        *)
            section_header "DNS Records — ${ZONE_NAME}"

            printf "  ${BOLD}%-34s %-6s %-18s %-26s %-6s${RESET}\n" \
                "RECORD_ID" "TYPE" "NAME" "VALUE" "TTL"
            printf "  %s\n" "$(printf '%.0s─' {1..92})"

            echo "$records" | jq -r \
                '.[] | "\(.id)\t\(.type)\t\(.name // "@")\t\(.value // "—")\t\(.ttl // 0)"' \
                2>/dev/null \
                | while IFS=$'\t' read -r rid rtype rname rvalue rttl; do
                    printf "  %-34s %-6s %-18s %-26s %-6s\n" \
                        "${rid:0:32}" "$rtype" "${rname:0:16}" "${rvalue:0:24}" "$rttl"
                done

            echo ""
            field "Records:" "$total"
            ;;
    esac
}

# ══════════════════════════════════════════════════════════════════════
#                          ADD
# ══════════════════════════════════════════════════════════════════════
do_add() {
    [[ -z "$ZONE_NAME" ]] && die "Specify --zone DOMAIN"
    [[ -z "$RECORD_TYPE" ]] && die "Specify --type TYPE"
    [[ -z "$RECORD_NAME" ]] && die "Specify --name NAME"
    [[ -z "$RECORD_VALUE" ]] && die "Specify --value VALUE"

    local zid
    zid=$(resolve_zone_id "$ZONE_NAME")

    local payload
    payload=$(jq -n \
        --arg zid "$zid" \
        --arg type "$RECORD_TYPE" \
        --arg name "$RECORD_NAME" \
        --arg value "$RECORD_VALUE" \
        --argjson ttl "$RECORD_TTL" \
        '{zone_id: $zid, type: $type, name: $name, value: $value, ttl: $ttl}')

    local resp
    resp=$(hdns_api POST "/records" -d "$payload")

    local rid
    rid=$(echo "$resp" | jq -r '.record.id // empty' 2>/dev/null)

    if [[ -n "$rid" ]]; then
        echo -e "  ${GREEN}✓${RESET} Record created: ${RECORD_TYPE} ${RECORD_NAME} → ${RECORD_VALUE} (ID: ${rid})"
        ((ACTION_OK++)) || true
    else
        local errmsg
        errmsg=$(echo "$resp" | jq -r '.error.message // .message // "unknown error"' 2>/dev/null)
        echo -e "  ${RED}✗${RESET} Failed to create record: ${errmsg}"
        ((ACTION_FAIL++)) || true
    fi
}

# ══════════════════════════════════════════════════════════════════════
#                          UPDATE
# ══════════════════════════════════════════════════════════════════════
do_update() {
    [[ -z "$RECORD_ID" ]] && die "Specify --record-id ID"
    [[ -z "$ZONE_NAME" ]] && die "Specify --zone DOMAIN"
    [[ -z "$RECORD_TYPE" ]] && die "Specify --type TYPE"
    [[ -z "$RECORD_NAME" ]] && die "Specify --name NAME"
    [[ -z "$RECORD_VALUE" ]] && die "Specify --value VALUE"

    local zid
    zid=$(resolve_zone_id "$ZONE_NAME")

    local payload
    payload=$(jq -n \
        --arg zid "$zid" \
        --arg type "$RECORD_TYPE" \
        --arg name "$RECORD_NAME" \
        --arg value "$RECORD_VALUE" \
        --argjson ttl "$RECORD_TTL" \
        '{zone_id: $zid, type: $type, name: $name, value: $value, ttl: $ttl}')

    local resp
    resp=$(hdns_api PUT "/records/${RECORD_ID}" -d "$payload")

    local rid
    rid=$(echo "$resp" | jq -r '.record.id // empty' 2>/dev/null)

    if [[ -n "$rid" ]]; then
        echo -e "  ${GREEN}✓${RESET} Record updated: ${RECORD_TYPE} ${RECORD_NAME} → ${RECORD_VALUE} (ID: ${rid})"
        ((ACTION_OK++)) || true
    else
        local errmsg
        errmsg=$(echo "$resp" | jq -r '.error.message // .message // "unknown error"' 2>/dev/null)
        echo -e "  ${RED}✗${RESET} Failed to update record: ${errmsg}"
        ((ACTION_FAIL++)) || true
    fi
}

# ══════════════════════════════════════════════════════════════════════
#                          DELETE
# ══════════════════════════════════════════════════════════════════════
do_delete() {
    [[ -z "$RECORD_ID" ]] && die "Specify --record-id ID"
    [[ "$FORCE" != "true" ]] && die "Delete is destructive — use --force to confirm"

    local resp
    resp=$(hdns_api DELETE "/records/${RECORD_ID}")

    echo -e "  ${GREEN}✓${RESET} Record deleted: ${RECORD_ID}"
    ((ACTION_OK++)) || true
}

# ══════════════════════════════════════════════════════════════════════
#                          EXPORT
# ══════════════════════════════════════════════════════════════════════
do_export() {
    [[ -z "$ZONE_NAME" ]] && die "Specify --zone DOMAIN"

    local zid
    zid=$(resolve_zone_id "$ZONE_NAME")

    local zone_data
    zone_data=$(hdns_api_raw GET "/zones/${zid}/export")

    if [[ -n "$EXPORT_FILE" ]]; then
        echo "$zone_data" > "$EXPORT_FILE"
        echo -e "  ${GREEN}✓${RESET} Zone exported to ${EXPORT_FILE}"
    else
        echo "$zone_data"
    fi
}

# ══════════════════════════════════════════════════════════════════════
#                          IMPORT
# ══════════════════════════════════════════════════════════════════════
do_import() {
    [[ -z "$ZONE_NAME" ]] && die "Specify --zone DOMAIN"
    [[ -z "$IMPORT_FILE" ]] && die "Specify --file FILE"
    [[ ! -f "$IMPORT_FILE" ]] && die "File not found: ${IMPORT_FILE}"
    [[ "$FORCE" != "true" ]] && die "Import replaces ALL zone records — use --force to confirm"

    local zid
    zid=$(resolve_zone_id "$ZONE_NAME")

    local zone_data
    zone_data=$(cat "$IMPORT_FILE")

    local http_code
    http_code=$(curl -s -o /tmp/hdm_resp.json -w "%{http_code}" \
        -X POST \
        -H "Auth-API-Token: ${HETZNER_DNS_TOKEN}" \
        -H "Content-Type: text/plain" \
        "https://dns.hetzner.com/api/v1/zones/${zid}/import" \
        --data-binary "$zone_data")

    if [[ "$http_code" =~ ^2 ]]; then
        echo -e "  ${GREEN}✓${RESET} Zone imported from ${IMPORT_FILE}"
        ((ACTION_OK++)) || true
    else
        local errmsg
        errmsg=$(jq -r '.error.message // .message // "unknown error"' /tmp/hdm_resp.json 2>/dev/null)
        echo -e "  ${RED}✗${RESET} Import failed: ${errmsg}"
        ((ACTION_FAIL++)) || true
    fi
}

# ══════════════════════════════════════════════════════════════════════
#                          BULK ADD
# ══════════════════════════════════════════════════════════════════════
do_bulk_add() {
    [[ -z "$ZONE_NAME" ]] && die "Specify --zone DOMAIN"
    [[ -z "$CSV_FILE" ]] && die "Specify --csv FILE"
    [[ ! -f "$CSV_FILE" ]] && die "CSV file not found: ${CSV_FILE}"

    local zid
    zid=$(resolve_zone_id "$ZONE_NAME")

    section_header "Bulk Add — ${ZONE_NAME}"

    local line_num=0
    while IFS=',' read -r rtype rname rvalue rttl; do
        ((line_num++)) || true
        [[ -z "$rtype" || "$rtype" =~ ^# ]] && continue
        rtype=$(echo "$rtype" | xargs)
        rname=$(echo "$rname" | xargs)
        rvalue=$(echo "$rvalue" | xargs)
        rttl=$(echo "${rttl:-3600}" | xargs)

        local payload
        payload=$(jq -n \
            --arg zid "$zid" \
            --arg type "$rtype" \
            --arg name "$rname" \
            --arg value "$rvalue" \
            --argjson ttl "$rttl" \
            '{zone_id: $zid, type: $type, name: $name, value: $value, ttl: $ttl}')

        local resp
        resp=$(hdns_api POST "/records" -d "$payload")

        local rid
        rid=$(echo "$resp" | jq -r '.record.id // empty' 2>/dev/null)

        if [[ -n "$rid" ]]; then
            echo -e "  ${GREEN}✓${RESET} ${rtype} ${rname} → ${rvalue} (line ${line_num})"
            ((ACTION_OK++)) || true
        else
            echo -e "  ${RED}✗${RESET} ${rtype} ${rname} → ${rvalue} (line ${line_num})"
            ((ACTION_FAIL++)) || true
        fi

        sleep 0.5
    done < "$CSV_FILE"

    echo ""
    field_color "Succeeded:" "${GREEN}${ACTION_OK}${RESET}"
    if [[ "$ACTION_FAIL" -gt 0 ]]; then
        field_color "Failed:" "${RED}${ACTION_FAIL}${RESET}"
    fi
}

# ══════════════════════════════════════════════════════════════════════
#                          AUDIT
# ══════════════════════════════════════════════════════════════════════
do_audit() {
    [[ -z "$ZONE_NAME" ]] && die "Specify --zone DOMAIN"

    local zid
    zid=$(resolve_zone_id "$ZONE_NAME")

    local resp
    resp=$(hdns_api GET "/records?zone_id=${zid}")
    local records
    records=$(echo "$resp" | jq '.records // []' 2>/dev/null)
    local total
    total=$(echo "$records" | jq 'length' 2>/dev/null || echo 0)

    local warnings=0

    if [[ "$OUTPUT_FORMAT" != "prometheus" ]]; then
        section_header "DNS Audit — ${ZONE_NAME}"
        field "Records:" "$total"
        echo ""
    fi

    # Check SOA
    local soa_count
    soa_count=$(echo "$records" | jq '[.[] | select(.type == "SOA")] | length' 2>/dev/null || echo 0)
    if [[ "$soa_count" -eq 0 ]]; then
        ((warnings++)) || true
        [[ "$OUTPUT_FORMAT" != "prometheus" ]] && echo -e "  ${YELLOW}⚠${RESET} No SOA record found"
    else
        [[ "$OUTPUT_FORMAT" != "prometheus" ]] && echo -e "  ${GREEN}✓${RESET} SOA record present"
    fi

    # Check NS
    local ns_count
    ns_count=$(echo "$records" | jq '[.[] | select(.type == "NS")] | length' 2>/dev/null || echo 0)
    if [[ "$ns_count" -eq 0 ]]; then
        ((warnings++)) || true
        [[ "$OUTPUT_FORMAT" != "prometheus" ]] && echo -e "  ${RED}✗${RESET} No NS records found"
    elif [[ "$ns_count" -lt 2 ]]; then
        ((warnings++)) || true
        [[ "$OUTPUT_FORMAT" != "prometheus" ]] && echo -e "  ${YELLOW}⚠${RESET} Only ${ns_count} NS record(s) — recommend at least 2"
    else
        [[ "$OUTPUT_FORMAT" != "prometheus" ]] && echo -e "  ${GREEN}✓${RESET} ${ns_count} NS records"
    fi

    # Check common types
    for rtype in A AAAA MX TXT; do
        local rcount
        rcount=$(echo "$records" | jq --arg t "$rtype" '[.[] | select(.type == $t)] | length' 2>/dev/null || echo 0)
        if [[ "$rcount" -eq 0 ]]; then
            ((warnings++)) || true
            [[ "$OUTPUT_FORMAT" != "prometheus" ]] && echo -e "  ${YELLOW}⚠${RESET} No ${rtype} records found"
        else
            [[ "$OUTPUT_FORMAT" != "prometheus" ]] && echo -e "  ${GREEN}✓${RESET} ${rcount} ${rtype} record(s)"
        fi
    done

    # Check low TTLs
    local low_ttl
    low_ttl=$(echo "$records" | jq '[.[] | select(.ttl < 300 and .ttl > 0)] | length' 2>/dev/null || echo 0)
    if [[ "$low_ttl" -gt 0 ]]; then
        ((warnings++)) || true
        [[ "$OUTPUT_FORMAT" != "prometheus" ]] && echo -e "  ${YELLOW}⚠${RESET} ${low_ttl} record(s) with TTL < 300s"
    else
        [[ "$OUTPUT_FORMAT" != "prometheus" ]] && echo -e "  ${GREEN}✓${RESET} All TTLs ≥ 300s"
    fi

    # Check wildcards
    local wildcard
    wildcard=$(echo "$records" | jq '[.[] | select(.name | startswith("*"))] | length' 2>/dev/null || echo 0)
    if [[ "$wildcard" -gt 0 ]]; then
        [[ "$OUTPUT_FORMAT" != "prometheus" ]] && echo -e "  ${CYAN}ℹ${RESET} ${wildcard} wildcard record(s)"
    fi

    if [[ "$OUTPUT_FORMAT" == "prometheus" ]]; then
        cat <<EOF
# HELP hetzner_dns_audit_warnings DNS audit warnings
# TYPE hetzner_dns_audit_warnings gauge
hetzner_dns_audit_warnings{zone="${ZONE_NAME}"} ${warnings}
EOF
        return
    fi

    echo ""
    if [[ "$warnings" -eq 0 ]]; then
        field_color "Warnings:" "${GREEN}0${RESET}"
    else
        field_color "Warnings:" "${YELLOW}${warnings}${RESET}"
    fi
}

# ══════════════════════════════════════════════════════════════════════
#                          HELP
# ══════════════════════════════════════════════════════════════════════
show_help() {
    cat <<EOF
${BOLD}${SCRIPT_NAME}${RESET} — Hetzner DNS Manager

Manage DNS zones and records via the Hetzner DNS API.

${BOLD}MODES${RESET}
  --zones           List all DNS zones
  --records         List records for a zone (requires --zone)
  --add             Add a DNS record
  --update          Update a DNS record (requires --record-id)
  --delete          Delete a DNS record (requires --record-id, --force)
  --export          Export zone in BIND format
  --import          Import zone from BIND file (requires --file, --force)
  --bulk-add        Bulk add records from CSV (requires --csv)
  --audit           Audit zone for common issues

${BOLD}TARGETING${RESET}
  --zone DOMAIN     Target zone by domain name (resolved to ID internally)
  --record-id ID    Target a specific record by ID

${BOLD}RECORD FIELDS${RESET}
  --type TYPE       Record type (A, AAAA, CNAME, MX, TXT, SRV, etc.)
  --name NAME       Record name — subdomain part (e.g., "www", "@" for apex)
  --value VALUE     Record value (e.g., IP address, hostname)
  --ttl TTL         TTL in seconds (default: 3600)

${BOLD}OPTIONS${RESET}
  --format FMT      Output: table, json, prometheus (default: table)
  --csv FILE        CSV file for bulk add (type,name,value,ttl)
  --file FILE       BIND zone file for import
  --output FILE     Write export to file instead of stdout
  --force           Required for delete and import operations
  --verbose         Debug output
  --no-color        Disable colored output
  --help            Show this help message

${BOLD}ENVIRONMENT VARIABLES${RESET}
  HETZNER_DNS_TOKEN  Hetzner DNS API token (required, separate from HCLOUD_TOKEN)
  HDM_FORMAT         Default output format
  VERBOSE            Enable verbose output (true/false)
  COLOR              Color mode: auto, always, never

${BOLD}EXAMPLES${RESET}
  # List all zones
  ${SCRIPT_NAME} --zones

  # List records for a zone
  ${SCRIPT_NAME} --records --zone example.com

  # Add an A record
  ${SCRIPT_NAME} --add --zone example.com --type A --name www --value 168.119.10.50

  # Add MX record with custom TTL
  ${SCRIPT_NAME} --add --zone example.com --type MX --name @ --value "10 mail.example.com" --ttl 7200

  # Update a record
  ${SCRIPT_NAME} --update --record-id abc123 --zone example.com --type A --name www --value 168.119.10.51

  # Delete a record
  ${SCRIPT_NAME} --delete --record-id abc123 --force

  # Export zone as BIND file
  ${SCRIPT_NAME} --export --zone example.com --output example.com.zone

  # Import BIND zone file
  ${SCRIPT_NAME} --import --zone example.com --file example.com.zone --force

  # Bulk add from CSV
  ${SCRIPT_NAME} --bulk-add --zone example.com --csv records.csv

  # Audit zone
  ${SCRIPT_NAME} --audit --zone example.com

  # Prometheus metrics
  ${SCRIPT_NAME} --zones --format prometheus

${BOLD}EXIT CODES${RESET}
  0   Success
  1   Runtime error
EOF
}

# ══════════════════════════════════════════════════════════════════════
#                          PARSE ARGS
# ══════════════════════════════════════════════════════════════════════
parse_args() {
    while [[ $# -gt 0 ]]; do
        case "$1" in
            --zones)       RUN_MODE="zones"; shift ;;
            --records)     RUN_MODE="records"; shift ;;
            --add)         RUN_MODE="add"; shift ;;
            --update)      RUN_MODE="update"; shift ;;
            --delete)      RUN_MODE="delete"; shift ;;
            --export)      RUN_MODE="export"; shift ;;
            --import)      RUN_MODE="import"; shift ;;
            --bulk-add)    RUN_MODE="bulk-add"; shift ;;
            --audit)       RUN_MODE="audit"; shift ;;
            --zone)        ZONE_NAME="${2:?--zone requires a DOMAIN}"; shift 2 ;;
            --record-id)   RECORD_ID="${2:?--record-id requires an ID}"; shift 2 ;;
            --type)        RECORD_TYPE="${2:?--type requires a TYPE}"; shift 2 ;;
            --name)        RECORD_NAME="${2:?--name requires a NAME}"; shift 2 ;;
            --value)       RECORD_VALUE="${2:?--value requires a VALUE}"; shift 2 ;;
            --ttl)         RECORD_TTL="${2:?--ttl requires a TTL}"; shift 2 ;;
            --csv)         CSV_FILE="${2:?--csv requires a FILE}"; shift 2 ;;
            --file)        IMPORT_FILE="${2:?--file requires a FILE}"; shift 2 ;;
            --output)      EXPORT_FILE="${2:?--output requires a FILE}"; shift 2 ;;
            --format)      OUTPUT_FORMAT="${2:?--format requires a value}"; shift 2 ;;
            --force)       FORCE="true"; shift ;;
            --verbose)     VERBOSE="true"; shift ;;
            --no-color)    COLOR="never"; shift ;;
            --help|-h)     setup_colors; show_help; exit 0 ;;
            *)             die "Unknown option: $1 (see --help)" ;;
        esac
    done
}

# ══════════════════════════════════════════════════════════════════════
#                          MAIN
# ══════════════════════════════════════════════════════════════════════
main() {
    parse_args "$@"
    setup_colors

    if [[ -z "$RUN_MODE" ]]; then
        err "No mode specified"
        echo ""
        show_help
        exit 1
    fi

    check_deps
    check_credentials

    START_TIME=$(date +%s)

    case "$RUN_MODE" in
        zones)    do_zones ;;
        records)  do_records ;;
        add)      do_add ;;
        update)   do_update ;;
        delete)   do_delete ;;
        export)   do_export ;;
        import)   do_import ;;
        bulk-add) do_bulk_add ;;
        audit)    do_audit ;;
        *)        die "Unknown mode: ${RUN_MODE}" ;;
    esac

    if [[ "$OUTPUT_FORMAT" != "prometheus" ]]; then
        echo ""
        field "Duration:" "$(elapsed)"
    fi
}

main "$@"
