#!/bin/bash

# Configuration variables
PROCESS_NAME="coredns"
PID_FILE="/tmp/coredns_last.pid"
CHECK_INTERVAL=5
UPDATE_DELAY_DAYS=3
TMP_FILE="/sdcard1/combined-blocklist.txt"
LAST_UPDATE_FILE="/sdcard1/last_update.txt"
URL_FILE_LIST="/sdcard1/urllist.txt"
BLOCKLIST_FILE="/run/utm/domain_list/domainlist_0.list"
REMOVE_FILE="/run/utm/domain_list/domainlist_1.list"
MERGED_LIST_TMP="/tmp/mergedlist.txt"

# Default URL list content
DEFAULT_URLS=$(cat << 'EOF'
https://adguardteam.github.io/HostlistsRegistry/assets/filter_27.txt
https://adguardteam.github.io/HostlistsRegistry/assets/filter_49.txt
https://adguardteam.github.io/HostlistsRegistry/assets/filter_1.txt
https://adguardteam.github.io/HostlistsRegistry/assets/filter_42.txt
https://adguardteam.github.io/HostlistsRegistry/assets/filter_18.txt
https://adguardteam.github.io/HostlistsRegistry/assets/filter_23.txt
https://adguardteam.github.io/HostlistsRegistry/assets/filter_11.txt
https://adguardteam.github.io/HostlistsRegistry/assets/filter_9.txt
https://adguardteam.github.io/HostlistsRegistry/assets/filter_50.txt
https://raw.githubusercontent.com/DandelionSprout/adfilt/master/Alternate%20versions%20Anti-Malware%20List/AntiMalwareHosts.txt
https://osint.digitalside.it/Threat-Intel/lists/latestdomains.txt
https://v.firebog.net/hosts/Prigent-Crypto.txt
https://phishing.army/download/phishing_army_blocklist_extended.txt
https://v.firebog.net/hosts/static/w3kbl.txt
EOF
)

# Parse command-line arguments for force
FORCE=0
while [[ $# -gt 0 ]]; do
    case "$1" in
        -f|--force)
            FORCE=1
            ;;
    esac
    shift
done

# Function to check if full update is needed
check_if_update_needed() {
    local lastupdatefile="$1"
    local update_delay_days="$2"
    local force="$3"

    if [[ -f "$lastupdatefile" ]]; then
        last_update_ts=$(cat "$lastupdatefile")
        now_ts=$(date +%s)

        # How many seconds must pass
        delay_seconds=$((update_delay_days * 86400))

        # If not forced and enough time has not passed → return 1 (skip full update)
        if [[ $force -eq 0 ]] && (( now_ts - last_update_ts < delay_seconds )); then
            return 1
        fi
    fi
    return 0
}

# Function to handle skipped update actions
handle_skipped_update() {
    local blocklistfile="$1"
    local tmpfile="$2"
    local update_delay_days="$3"

    echo "$(date): Full Update skipped — last update was less than $update_delay_days days ago. Use -f or --force to override."
    if cmp -s "$blocklistfile" "$tmpfile" ; then
        echo "$(date): Custom Blocklist still in use, doing nothing."
    else
        sleep 10
        echo "$(date): Copying existing blocklist to $blocklistfile"
        sort "$blocklistfile" "$tmpfile" | uniq > "$MERGED_LIST_TMP"
        mv "$MERGED_LIST_TMP" "$blocklistfile"
        echo "$(date): Restarting CoreDNS to apply new blocklist file."
        pkill coredns
    fi
}

# Function to create default URL list if not exists
create_default_url_list() {
    local url_file_list="$1"
    local default_urls="$2"

    if [ ! -f "$url_file_list" ]; then
        echo "$(date): Using Default url list: $url_file_list"
        echo "$default_urls" > "$url_file_list"
    fi
}

# Function to fetch and merge sources
fetch_and_merge_sources() {
    local blocklistfile="$1"
    local url_file_list="$2"
    local tmpfile="$3"

    touch "$tmpfile"
    {
      # existing file
      cat "$blocklistfile"

      # URL sources from file
      while IFS= read -r url; do
        # Trim leading/trailing whitespace
        url="$(echo "$url" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//')"

        # Skip empty or commented lines
        [ -z "$url" ] && continue
        case "$url" in
          \#*|\!* ) continue ;;
        esac
        # Fetch & clean
        curl -s "$url" \
          | grep -v '^[!#]' \
          | sed '/^\s*$/d' \
          | sed 's/^||//' \
          | sed 's/\^$//'

      done < "$url_file_list"
    } | sort -u \
      | grep -Ev '^\.' \
      | grep -Ev '^\*-' \
      | grep -Ev '^-' \
      | grep -Ev '^/' \
      | grep -Ev '\*' \
      | grep -E '^[a-zA-Z0-9][a-zA-Z0-9.-]*\.[a-zA-Z]{2,}$' \
      > "$tmpfile"

    echo "$(date): Combined List cleanup."
}

# Function to apply removal rules using AWK
apply_removal_rules() {
    local tmpfile="$1"
    local removefile="$2"

    awk -v patfile="$removefile" '
    BEGIN {
        # load removal rules
        while ((getline rule < patfile) > 0) {
            # skip empty lines / pure whitespace
            if (rule ~ /^[ \t]*$/) continue

            # Escape regex special chars except *
            gsub(/[][(){}+?.\\^$|]/, "\\\\&", rule)

            # Convert * into .*
            gsub(/\*/, ".*", rule)

            patterns[++n] = "^" rule "$"
        }
    }

    {
        drop = 0
        # Check against each pattern
        for (i = 1; i <= n; i++) {
            if ($0 ~ patterns[i]) {
                drop = 1
                break
            }
        }
        if (!drop) print
    }
    ' "$tmpfile" > "${tmpfile}.filtered"
}

# Function to finalize the blocklist
finalize_blocklist() {
    local tmpfile="$1"
    local blocklistfile="$2"
    local lastupdatefile="$3"

    mv "${tmpfile}.filtered" "$tmpfile"
    cp "$tmpfile" "$blocklistfile"

    # Save update timestamp.
    date +%s > "$lastupdatefile"

    echo "$(date): Restarting CoreDNS to apply new blocklist file"
    pkill coredns
    echo "$(date): Blocklist created at: $blocklistfile with size $(du -sh $blocklistfile) and $(wc -l < $blocklistfile) lines"
}

# Main function to update the blocklist
update_blocklist() {
    local force="$1"

    if check_if_update_needed "$LAST_UPDATE_FILE" "$UPDATE_DELAY_DAYS" "$force"; then
        create_default_url_list "$URL_FILE_LIST" "$DEFAULT_URLS"
        fetch_and_merge_sources "$BLOCKLIST_FILE" "$URL_FILE_LIST" "$TMP_FILE"
        apply_removal_rules "$TMP_FILE" "$REMOVE_FILE"
        finalize_blocklist "$TMP_FILE" "$BLOCKLIST_FILE" "$LAST_UPDATE_FILE"
    else
        handle_skipped_update "$BLOCKLIST_FILE" "$TMP_FILE" "$UPDATE_DELAY_DAYS"
    fi
}

echo "$(date): Starting PID check..."

while true; do
    # Load last PID from file
    LAST_PID=""
    [[ -f "$PID_FILE" ]] && LAST_PID=$(cat "$PID_FILE")

    # Get current PID
    CURRENT_PID=$(pgrep -f "$PROCESS_NAME")

    if [[ -n "$CURRENT_PID" ]]; then
        # Process is running
        if [[ "$CURRENT_PID" != "$LAST_PID" ]]; then
            echo "$(date): PID changed: $LAST_PID -> $CURRENT_PID"
            echo "$(date): Running Blocklist update"

            # Call the update function with the global FORCE
            update_blocklist "$FORCE"

            # Update PID file
            sleep 2
            CURRENT_PID=$(pgrep -f "$PROCESS_NAME")
            echo "$CURRENT_PID" > "$PID_FILE"
        fi
    else
        # Process not running
        echo "$(date): $PROCESS_NAME not running!"

        # Reset PID file
        echo "" > "$PID_FILE"
    fi

    sleep $CHECK_INTERVAL
done
