#!/usr/bin/env bash
set -o pipefail -o errexit -o nounset

# Copyright 2024 Google Inc. All rights reserved.

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

if [ $(uname) == "Darwin" ]; then
    echo "WARNING: You are on a macos, you need to run 'brew install coreutils gnu-sed' to install required packages."
    echo ""
    export PATH="/opt/homebrew/opt/coreutils/libexec/gnubin:$PATH"
    export PATH="/opt/homebrew/opt/gnu-sed/libexec/gnubin:$PATH"
fi

function cmd_lock() {
    echo "🚧 Querying for repos (temporarily using hardcoded repos)"
    echo ""
    # temporarily hardcode right now (query doesn't work after bzl mod)
    local repos=$(cat <<EOL
bookworm
bookworm_java
bookworm_python
EOL
)
    #repos=$(bazel query "kind('deb_package_index', //external:*)" --output=label 2>/dev/null | cut -d: -f2)

    for repo in $repos; do
      for i in $(seq 10); do
        echo "🔑 Locking $repo (attempt ${i})"
        bazel run "@${repo}//:lock" && break || sleep 20;
        if [[ $i -eq 10 ]]; then
          echo ""
          echo "Failed to lock $repo after 10 attempts" >&2
          exit 1
        fi
      done
    done
}

function find_latest_snapshot() {
    local type="$1"
    # If it's the first of the month, look at the last month, otherwise this -1 day has no effect since searches
    # occur at the "month" level. This is an intentional buffer added to get the snapshots fully hydrated. We
    # intentionally don't include complicated logic for the case where it's after the 1st and no snapshots are
    # availalbe for the month (it's extremely unlikely for our updater to run into this situation unless the
    # snapshot serving infrastructure is acting up).
    local current="$(date -d '-1 day' +%Y-%m-%d)"
    local tmp=$(mktemp)
    local q=$(date -d "$current" +"year=%Y&month=%m")
    if curl -fs "https://snapshot.debian.org/archive/debian/?$q" | grep -ohE "([0-9]+T[0-9]+Z)" > $tmp; then
      # same logic as above, find the newest snapshot that isn't "today"
      today=$(date +"%Y%m%dT")
      cat $tmp | grep -v $today | tail -n1
    fi
}

function cmd_update_snapshots() {
    echo "🧐 Looking for updates... "
    latest=$(find_latest_snapshot "debian")
    latest_security=$(find_latest_snapshot "debian-security")
    if [[ -z "$latest" || -z "$latest_security" ]]; then
        echo ""
        echo "could not find any snapshots for debian or debian-security"
        exit 1
    fi
    echo ""
    echo "🎯 Found snapshots"
    echo "   debian: $latest"
    echo "   security: $latest_security"
    echo ""

    # if tty ask for approval
    if [ -t 1 ]; then
        read -p "Do you want to continue? (y/n) " -n 1 -r
        sleep 0.5
        echo $'\n'
        if [[ ! "$REPLY" =~ ^[Yy]$ ]]; then
            echo "Aborting..."
            exit 0
        fi
    fi

    for mpath in "./private/repos/deb/"*.yaml; do
        current=$(grep -oE "debian/([0-9]+T[0-9]+Z)" $mpath | cut -d/ -f2 | head -n1)
        current_security=$(grep -oE "debian-security/([0-9]+T[0-9]+Z)" $mpath | cut -d/ -f2 | head -n1)

        if [[ "$current" == "$latest" && "$current_security" == "$latest_security" ]]; then
            echo "🎖️ $mpath is up to date."
            continue
        fi
        echo "🗞️ $mpath"
        if [[ "$current" != "$latest" ]]; then
            sed -i -E "s/(debian\/)([0-9]+T[0-9]+Z)/\1$latest/" "$mpath"
            echo "   debian: $current -> $latest"
        fi
        if [[ "$current_security" != "$latest_security" ]]; then
            sed -i -E "s/(debian-security\/)([0-9]+T[0-9]+Z)/\1$latest_security/" "$mpath"
            echo "   debian-security: $current_security -> $latest_security"
        fi
        echo ""
    done
    echo ""
    echo "👌 Done..."
}

# write DISTROLESS_DIFF to GITHUB_ENV if changes are made
function cmd_github_update_snapshots() {
    local tmp=$(mktemp -d)
    jq -nr 'inputs.packages[] | .key + " " + .sha256' ./private/repos/deb/*.lock.json | sort > "$tmp/old.hashes"
    cmd_update_snapshots
    cmd_lock
    jq -nr 'inputs.packages[] | .key + " " + .sha256' ./private/repos/deb/*.lock.json | sort > "$tmp/new.hashes"
    diff "$tmp/old.hashes" "$tmp/new.hashes" | tee "$tmp/diff" || printf "DISTROLESS_DIFF<<EOF\n$(<$tmp/diff)\nEOF" >> "$GITHUB_ENV"
}

function cmd_lint () {
    echo "🧹 Linting"
    echo ""
    if ! which buildifier > /dev/null; then
        echo "🧱 No buildifier executable was found."
        echo " Did you follow the ./CONTRIBUTING.md ?"
        exit 1
    fi
    buildifier -mode=fix $(find . -name 'BUILD*' -o -name 'WORKSPACE*' -o -name '*.bzl' -type f)
}

function cmd_update_java_archives () {
    source scripts/update_java_archives.sh
    old_version=$(get_java_version)
    generate_java_archives > private/repos/java.MODULE.bazel
    new_version=$(get_java_version)
    update_test_versions_java21 $old_version $new_version
}

function cmd_test () {
    echo "🧪 Testing"
    echo ""

    local arch=$(uname -m)

    echo "💡 only including image tests for $arch"
    echo ""

    arch_specific_targets=$(bazel query "attr(\"tags\", "$arch", \"//...\")")

    # Run all tests tagged with "amd64"
    bazel test --test_timeout=900 //... $arch_specific_targets
}


case "${1:-"~~nocmd"}" in
lock)
    cmd_lock
    ;;
update-snapshots)
    cmd_update_snapshots
    ;;
lint)
    cmd_lint
    ;;
github-update-snapshots)
    cmd_github_update_snapshots
    ;;
test)
    cmd_test
    ;;
update-java-archives)
    cmd_update_java_archives
    ;;
~~nocmd) # no command provided
    echo "provide a command: lock, update-snapshots, github-update-snapshots, update-java-archives, test"
    exit 1
    ;;
*) # unknown command
    echo "unknown command $1"
    exit 1
    ;;
esac
