#!/bin/bash

# Function to print usage information
usage() {
    echo "Usage: $0 <image> <start_tag> <end_tag>"
    echo "Example: $0 tabledevil/sep 230101 230916"
    exit 1
}

# Function to get today's date in YYMMDD format
get_today() {
    date +%y%m%d
}

# Assign arguments to variables or use defaults
image="${1:-tabledevil/sep}"
start_tag="$2"
end_tag="${3:-$(get_today)}"
IMAGE_REPOSITORY=$(echo "$image" | cut -d'/' -f1)
IMAGE_NAME=$(echo "$image" | cut -d'/' -f2)

PATTERN="Threat Found!"

# Validate that start_tag and end_tag are in the correct format
if ! [[ "$start_tag" =~ ^[0-9]{6}$ ]] || ! [[ "$end_tag" =~ ^[0-9]{6}$ ]]; then
    echo "Error: Tags must be in YYMMDD format."
    usage
fi

# Function to get Docker Hub token using PAT
get_token() {
    if [ -z "$DOCKER_USERNAME" ]; then
        read -p "Enter Docker Hub username: " DOCKER_USERNAME
    fi
    if [ -z "$DOCKER_PAT" ]; then
        read -sp "Enter Docker Hub token: " DOCKER_PAT
        echo
    fi
    TOKEN=$(curl -s -H "Content-Type: application/json" -X POST -d '{"username": "'${DOCKER_USERNAME}'", "password": "'${DOCKER_PAT}'"}' https://hub.docker.com/v2/users/login/ | jq -r .token)
    if [ "$TOKEN" == "null" ]; then
        echo "Failed to get token. Please check your credentials."
        exit 1
    fi
}

# Function to get tags for a repository
get_tags() {
    PAGE=1
    PAGE_SIZE=100
    TAGS=()

    while true; do
        if [ -n "$TOKEN" ]; then
            RESPONSE=$(curl -s -H "Authorization: JWT ${TOKEN}" "https://hub.docker.com/v2/repositories/${IMAGE_REPOSITORY}/${IMAGE_NAME}/tags/?page_size=${PAGE_SIZE}&page=${PAGE}")
        else
            RESPONSE=$(curl -s "https://hub.docker.com/v2/repositories/${IMAGE_REPOSITORY}/${IMAGE_NAME}/tags/?page_size=${PAGE_SIZE}&page=${PAGE}")
        fi
        TAGS_PAGE=$(echo $RESPONSE | jq -r '.results[].name')
        TAGS+=($TAGS_PAGE)

        NEXT=$(echo $RESPONSE | jq -r '.next')
        if [ "$NEXT" == "null" ]; then
            break
        fi
        PAGE=$((PAGE + 1))
    done

    echo "${TAGS[@]}"
}

# Function to filter tags based on date range
filter_tags_by_date() {
    local tags=("$@")
    local filtered=()
    local start="$start_tag"
    local end="$end_tag"

    for tag in "${tags[@]}"; do
        if [[ "$tag" =~ ^[0-9]{6}$ ]]; then
            if [[ "$tag" -ge "$start" && "$tag" -le "$end" ]]; then
                filtered+=("$tag")
            fi
        fi
    done

    echo "${filtered[@]}"
}

# Function to check for malware in the given Docker tag
check_malware() {
    local tag=$1
    echo -n "Checking $image:$tag "
    result=$(docker run -it --rm -v "$(pwd):/data:ro" --network=none "$image:$tag" scan)
    if echo "$result" | grep -q "$PATTERN"; then
        echo "Pattern found"
        return 0
    else
        echo "Pattern NOT found"
        return 1
    fi
}

# Function to run the binary search
binary_search() {
    local tags=("$@")
    local low=0
    local high=$(( ${#tags[@]} - 1 ))
    local mid

    # Determine the initial states for low and high
    check_malware "${tags[$low]}"
    local low_result=$?
    
    check_malware "${tags[$high]}"
    local high_result=$?

    # If the results for low and high are the same, there is no switch point in the range
    if [ $low_result -eq $high_result ]; then
        echo "No change in detection within the tag range."
        return
    fi

    # Binary search to find the exact switching point
    while [ $((low + 1)) -lt $high ]; do
        mid=$(((low + high) / 2))
        check_malware "${tags[$mid]}"
        local mid_result=$?

        if [ $mid_result -eq $low_result ]; then
            low=$mid
        else
            high=$mid
        fi
    done

    # Output the tag of the first image that finds the malware switch
    echo "The detection changes between tags: ${tags[$low]} - ${tags[$high]}"
}


# Main script execution

# Try to retrieve all tags without authentication
echo "Retrieving all tags for $image from Docker Hub..."
all_tags=($(get_tags))
echo $all_tags

# If tags retrieval failed, prompt for credentials and retry
if [ ${#all_tags[@]} -eq 0 ]; then
    echo "Failed to retrieve tags without authentication. Trying with credentials..."
    get_token
    all_tags=($(get_tags))
    if [ ${#all_tags[@]} -eq 0 ]; then
        echo "Failed to retrieve tags even with authentication."
        exit 1
    fi
fi

# Filter tags to include only those within the date range
echo "Filtering tags from $start_tag to $end_tag..."
filtered_tags=($(filter_tags_by_date "${all_tags[@]}"))

# Run the binary search on the filtered tags
echo "Running binary search on the filtered tags..."
binary_search "${filtered_tags[@]}"
