#!/bin/bash

SETTINGS_FILE="/var/efw/ddns/settings"
LOG_FILE="/var/log/messages"
CRON_DIR="/etc/cron.d"
LAST_CHANGE_FILE="/var/log/ddns_last_change"

URL_CHECK_IFCONFIG="https://ifconfig.me"
URL_CHECK_ICANHAZIP="https://icanhazip.com"
URL_API_CLOUDFLARE="https://api.cloudflare.com/client/v4/zones"
URL_API_DUCKDNS="https://www.duckdns.org/update"
URL_API_NOIP="https://dynupdate.no-ip.com/nic/update"
URL_API_DYNDNS="https://members.dyndns.org/nic/update"
URL_API_FREEMYIP="https://freemyip.com/update"

TARGET_ID="$1"

generate_independent_cron_files() {
    /bin/rm -f $CRON_DIR/ddns-update-* 2>/dev/null || true

    local line_id=0
    while IFS=',' read -r interface provider var1 var2 var3 var4 var5 var6 var7 var8 var9
    do
        ((line_id++))
        
        interface=$(/bin/echo "$interface" | /usr/bin/tr -d ' ')
        provider=$(/bin/echo "$provider" | /usr/bin/tr -d ' ')
        status=$(/bin/echo "$var7" | /usr/bin/tr -d ' ')
        interval=$(/bin/echo "$var8" | /usr/bin/tr -d ' ')

        [ -z "$interface" ] && continue
        [[ "$interface" == \#* ]] && continue
        
        local clean_provider=$(/bin/echo "$provider" | /usr/bin/tr '.')
        clean_provider=$(/bin/echo "$provider" | /usr/bin/tr '.' '_')
        
        if [ -z "$clean_provider" ]; then
            clean_provider="service_$line_id"
        fi
        
        local INDIVIDUAL_CRON="$CRON_DIR/ddns-update-$clean_provider"

        if [ "$status" != "on" ]; then
            /bin/rm -f "$INDIVIDUAL_CRON" 2>/dev/null || true
            continue
        fi

        if [ -z "$interval" ] || ! [[ "$interval" =~ ^[0-9]+$ ]]; then
            interval=60
        fi

        /bin/cat > "$INDIVIDUAL_CRON" <<EOF
# INDEPENDENT DDNS SCHEDULER - $provider (ID $line_id)
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin

EOF

        if [ "$interval" -ge 60 ]; then
            local minutes=$((interval / 60))
            /bin/echo "*/$minutes * * * * /usr/local/bin/ddns-clients $line_id >/dev/null 2>&1" >> "$INDIVIDUAL_CRON"
        else
            /bin/echo "* * * * * /usr/local/bin/ddns-clients $line_id >/dev/null 2>&1" >> "$INDIVIDUAL_CRON"
            
            local accumulated_sleep=0
            while [ $((accumulated_sleep + interval)) -lt 60 ]
            do
                accumulated_sleep=$((accumulated_sleep + interval))
                /bin/echo "* * * * * (sleep $accumulated_sleep ; /usr/local/bin/ddns-clients $line_id >/dev/null 2>&1) &" >> "$INDIVIDUAL_CRON"
            done
        fi

        /bin/chmod 644 "$INDIVIDUAL_CRON" 2>/dev/null
        
    done < <(/bin/sed 's/\r//g' "$SETTINGS_FILE")

    /etc/init.d/fcron restart >/dev/null 2>&1 || true
}

process_update() {
    local RUN_IFACE="$1"
    local RUN_PROVIDER="$2"
    local RUN_VAR1="$3"
    local RUN_VAR2="$4"
    local RUN_VAR5="$5"
    local RUN_VAR6="$6"
    local RUN_FALLBACK="$7"

    local CURRENT_IP=""
    local LOG_PREFIX=$(/bin/date "+%b %d %H:%M:%S $(/bin/hostname -s) ddns[$$]:")

    if [ -z "$CURRENT_IP" ]; then CURRENT_IP=$(/usr/bin/curl -4 -s --interface "$RUN_IFACE" "$URL_CHECK_IFCONFIG"); fi
    if [ -z "$CURRENT_IP" ]; then CURRENT_IP=$(/usr/bin/curl -4 -s --interface "$RUN_IFACE" "$URL_CHECK_IFCONFIG"); fi

    if [ -z "$CURRENT_IP" ]; then
        /bin/echo "$LOG_PREFIX [WARNING] [$RUN_IFACE] Failed to connect to ifconfig.me. Trying fallback provider." >> "$LOG_FILE"
    fi

    if [ -z "$CURRENT_IP" ]; then CURRENT_IP=$(/usr/bin/curl -4 -s --interface "$RUN_IFACE" "$URL_CHECK_ICANHAZIP" | /usr/bin/tr -d '\r\n '); fi
    if [ -z "$CURRENT_IP" ]; then CURRENT_IP=$(/usr/bin/curl -4 -s --interface "$RUN_IFACE" "$URL_CHECK_ICANHAZIP" | /usr/bin/tr -d '\r\n '); fi

    if [ -z "$CURRENT_IP" ]; then
        if [ "$RUN_FALLBACK" == "on" ]; then
            /bin/echo "$LOG_PREFIX [WARNING] [$RUN_IFACE] Failed to connect to icanhazip.com. Switching to default route (no interface restriction)." >> "$LOG_FILE"
        else
            /bin/echo "$LOG_PREFIX [ERROR] [$RUN_IFACE] Failed to connect via specified interface and Fallback Route is disabled. Aborting update." >> "$LOG_FILE"
            return
        fi
    fi

    if [ -z "$CURRENT_IP" ]; then
        /bin/rm -f "/tmp/ddns_cache_${RUN_IFACE}_${RUN_PROVIDER}" 2>/dev/null

        CURRENT_IP=$(/usr/bin/curl -4 -s "$URL_CHECK_IFCONFIG")
        
        if [ -z "$CURRENT_IP" ]; then
            CURRENT_IP=$(/usr/bin/curl -4 -s "$URL_CHECK_ICANHAZIP" | /usr/bin/tr -d '\r\n ')
        fi
        
        local IFACE_PARAM=""
    else
        local IFACE_PARAM="--interface $RUN_IFACE"
    fi

    if [ -z "$CURRENT_IP" ] ; then
        /bin/echo "$LOG_PREFIX [ERROR] Could not obtain IP for interface $RUN_IFACE (even via default route)" >> "$LOG_FILE"
        return
    fi

    local CACHE_FILE="/tmp/ddns_cache_${RUN_IFACE}_${RUN_PROVIDER}"
    local OLD_IP=""
    [ -f "$CACHE_FILE" ] && OLD_IP=$(/bin/cat "$CACHE_FILE")

    if [ "$CURRENT_IP" == "$OLD_IP" ]; then
        return
    fi

    local log_date=$(/bin/date '+%b %d %H:%M:%S')
    local nova_linha_metadata="LAST_UPDATE=\"$log_date\" INTERFACE=\"$RUN_IFACE\" PROVIDER=\"$RUN_PROVIDER\" OLD_IP=\"$OLD_IP\" NEW_IP=\"$CURRENT_IP\""

    /bin/touch "$LAST_CHANGE_FILE"
    if /bin/grep -q "INTERFACE=\"$RUN_IFACE\"" "$LAST_CHANGE_FILE" && /bin/grep -q "PROVIDER=\"$RUN_PROVIDER\"" "$LAST_CHANGE_FILE"; then
        /bin/sed -i "/INTERFACE=\"$RUN_IFACE\"/ { /PROVIDER=\"$RUN_PROVIDER\"/ d; }" "$LAST_CHANGE_FILE"
        /bin/echo "$nova_linha_metadata" >> "$LAST_CHANGE_FILE"
    else
        /bin/echo "$nova_linha_metadata" >> "$LAST_CHANGE_FILE"
    fi

    /bin/echo "$LOG_PREFIX [NOTICE] [$RUN_IFACE] IP changed from $OLD_IP to $CURRENT_IP. Updating providers." >> "$LOG_FILE"

    case "$RUN_PROVIDER" in
        "cloudflare")
            local ZONE_ID=$(/bin/echo "$RUN_VAR1" | /usr/bin/tr -d '\r\n ')
            local SUBDOMAIN=$(/bin/echo "$RUN_VAR2" | /usr/bin/tr -d '\r\n ')
            local TOKEN=$(/bin/echo "$RUN_VAR6" | /usr/bin/tr -d '\r\n ')
            
            local RECORD_ID=$(/usr/bin/curl -s -X GET "$URL_API_CLOUDFLARE/$ZONE_ID/dns_records?type=A&name=$SUBDOMAIN" \
                -H "Authorization: Bearer $TOKEN" \
                -H "Content-Type: application/json" | /bin/grep -o '"id":"[^"]*' | /usr/bin/head -n 1 | /usr/bin/cut -d'"' -f4)

            if [ -z "$RECORD_ID" ]; then
                /bin/echo "$LOG_PREFIX [ERROR] [$RUN_IFACE] Record ID not found for $SUBDOMAIN." >> "$LOG_FILE"
                return
            fi
            
            local PAYLOAD="{\"type\":\"A\",\"name\":\"$SUBDOMAIN\",\"content\":\"$CURRENT_IP\",\"ttl\":120,\"proxied\":false}"
            local RESPONSE=$(/usr/bin/curl -4 -s $IFACE_PARAM -X PUT "$URL_API_CLOUDFLARE/$ZONE_ID/dns_records/$RECORD_ID" \
                -H "Authorization: Bearer $TOKEN" \
                -H "Content-Type: application/json" \
                --data "$PAYLOAD")
            
            if /bin/echo "$RESPONSE" | /bin/grep -q '"success":true'; then
                /bin/echo "$LOG_PREFIX [SUCCESS] [$RUN_IFACE] Cloudflare ($SUBDOMAIN) updated to $CURRENT_IP." >> "$LOG_FILE"
                /bin/echo "$CURRENT_IP" > "$CACHE_FILE"
            else
                /bin/echo "$LOG_PREFIX [ERROR] [$RUN_IFACE] Cloudflare failure: $RESPONSE" >> "$LOG_FILE"
            fi
            ;;

        "duckdns.org"|"duckdns")
            local DOMAIN=$(/bin/echo "$RUN_VAR1" | /usr/bin/tr -d '\r\n ')
            local TOKEN=$(/bin/echo "$RUN_VAR6" | /usr/bin/tr -d '\r\n ')
            
            local RESPONSE=$(/usr/bin/curl -4 -s $IFACE_PARAM "$URL_API_DUCKDNS?domains=$DOMAIN&token=$TOKEN&ip=$CURRENT_IP")
            
            if [ "$RESPONSE" = "OK" ]; then
                /bin/echo "$LOG_PREFIX [SUCCESS] [$RUN_IFACE] DuckDNS ($DOMAIN.duckdns.org) updated to $CURRENT_IP." >> "$LOG_FILE"
                /bin/echo "$CURRENT_IP" > "$CACHE_FILE"
            else
                /bin/echo "$LOG_PREFIX [ERROR] [$RUN_IFACE] DuckDNS failure: $RESPONSE" >> "$LOG_FILE"
            fi
            ;;

        "no-ip.com"|"noip")
            local HOSTNAME=$(/bin/echo "$RUN_VAR1" | /usr/bin/tr -d '\r\n ')
            local DOMAIN=$(/bin/echo "$RUN_VAR2" | /usr/bin/tr -d '\r\n ')
            local USERNAME=$(/bin/echo "$RUN_VAR5" | /usr/bin/tr -d '\r\n ')
            local PASSWORD=$(/bin/echo "$RUN_VAR6" | /usr/bin/tr -d '\r\n ')
            
            local FULL_HOST="$HOSTNAME"
            if [ -n "$DOMAIN" ] && [ "$DOMAIN" != "-" ]; then
                FULL_HOST="${HOSTNAME}.${DOMAIN}"
            fi

            local RESPONSE=$(/usr/bin/curl -4 -k -s $IFACE_PARAM -u "$USERNAME:$PASSWORD" -A "OpenFW" "$URL_API_NOIP?hostname=$FULL_HOST&myip=$CURRENT_IP")
            
            if /bin/echo "$RESPONSE" | /bin/grep -qE "nochg|good"; then
                /bin/echo "$LOG_PREFIX [SUCCESS] [$RUN_IFACE] No-IP ($FULL_HOST) updated to $CURRENT_IP." >> "$LOG_FILE"
                /bin/echo "$CURRENT_IP" > "$CACHE_FILE"
            else
                /bin/echo "$LOG_PREFIX [ERROR] [$RUN_IFACE] No-IP failure: $RESPONSE" >> "$LOG_FILE"
            fi
            ;;

        "dyndns.org"|"dyndns"|"syndns")
            local HOSTNAME=$(/bin/echo "$RUN_VAR1" | /usr/bin/tr -d '\r\n ')
            local DOMAIN=$(/bin/echo "$RUN_VAR2" | /usr/bin/tr -d '\r\n ')
            local USERNAME=$(/bin/echo "$RUN_VAR5" | /usr/bin/tr -d '\r\n ')
            local PASSWORD=$(/bin/echo "$RUN_VAR6" | /usr/bin/tr -d '\r\n ')
            
            local FULL_HOST="$HOSTNAME"
            if [ -n "$DOMAIN" ] && [ "$DOMAIN" != "-" ]; then
                FULL_HOST="${HOSTNAME}.${DOMAIN}"
            fi

            local RESPONSE=$(/usr/bin/curl -4 -k -s $IFACE_PARAM -u "$USERNAME:$PASSWORD" -A "OpenFW" "$URL_API_DYNDNS?hostname=$FULL_HOST&myip=$CURRENT_IP")
            
            if /bin/echo "$RESPONSE" | /bin/grep -qE "nochg|good"; then
                /bin/echo "$LOG_PREFIX [SUCCESS] [$RUN_IFACE] DynDNS/SynDNS ($FULL_HOST) updated to $CURRENT_IP." >> "$LOG_FILE"
                /bin/echo "$CURRENT_IP" > "$CACHE_FILE"
            else
                /bin/echo "$LOG_PREFIX [ERROR] [$RUN_IFACE] DynDNS/SynDNS failure: $RESPONSE" >> "$LOG_FILE"
            fi
            ;;

        "freemyip.com"|"freemyip")
            local FULL_DOMAIN=$(/bin/echo "$RUN_VAR1" | /usr/bin/tr -d '\r\n ')
            local TOKEN=$(/bin/echo "$RUN_VAR6" | /usr/bin/tr -d '\r\n ')

            local RESPONSE=$(/usr/bin/curl -4 -s $IFACE_PARAM "$URL_API_FREEMYIP?token=$TOKEN&domain=$FULL_DOMAIN&myip=$CURRENT_IP")
            
            if /bin/echo "$RESPONSE" | /bin/grep -q "OK"; then
                /bin/echo "$LOG_PREFIX [SUCCESS] [$RUN_IFACE] FreeMyIP ($FULL_DOMAIN) updated to $CURRENT_IP." >> "$LOG_FILE"
                /bin/echo "$CURRENT_IP" > "$CACHE_FILE"
            else
                /bin/echo "$LOG_PREFIX [ERROR] [$RUN_IFACE] FreeMyIP failure: $RESPONSE" >> "$LOG_FILE"
            fi
            ;;
    esac
}

if [ "$TARGET_ID" == "cron" ]; then
    if [ -f "$SETTINGS_FILE" ]; then
        generate_independent_cron_files
    fi
    exit 0
fi

if [ "$TARGET_ID" == "force" ]; then
    /bin/rm -f /tmp/ddns_cache_*
    TARGET_ID=""
    if [ -f "$SETTINGS_FILE" ]; then
        generate_independent_cron_files
    fi
fi

if [ -z "$TARGET_ID" ]; then
    if [ -f "$SETTINGS_FILE" ]; then
        generate_independent_cron_files
    fi
fi

if [ -f "$SETTINGS_FILE" ]; then
    line_id=0
    while IFS=',' read -r interface provider var1 var2 var3 var4 var5 var6 var7 var8 var9
    do
        ((line_id++))
        
        if [ -n "$TARGET_ID" ] && [ "$line_id" -ne "$TARGET_ID" ]; then
            continue
        fi

        interface=$(/bin/echo "$interface" | /usr/bin/tr -d '\r\n ')
        provider=$(/bin/echo "$provider" | /usr/bin/tr -d '\r\n ')
        var1=$(/bin/echo "$var1" | /usr/bin/tr -d '\r\n ')
        var2=$(/bin/echo "$var2" | /usr/bin/tr -d '\r\n ')
        var5=$(/bin/echo "$var5" | /usr/bin/tr -d '\r\n ')
        var6=$(/bin/echo "$var6" | /usr/bin/tr -d '\r\n ')
        status=$(/bin/echo "$var7" | /usr/bin/tr -d '\r\n ')
        fallback=$(/bin/echo "$var9" | /usr/bin/tr -d '\r\n ')
        
        [ -z "$fallback" ] && fallback="on"
        
        if [ "$status" == "on" ] && [ -n "$interface" ]; then
            process_update "$interface" "$provider" "$var1" "$var2" "$var5" "$var6" "$fallback"
        fi
    done < "$SETTINGS_FILE"
fi