#!/bin/bash

function wait_workflow_run_to_merge() {
    set +e # Ignore error when gh command fails
    local workflow="$1"
    local repo="$2"
    local timeout="${3:-180}"  # Default to 3 minutes
    local interval="${4:-10}"  # Default to 10 seconds

    sleep 10 # hack: gh don't support output the run id yet, simply wait for the workflow.
    # Get the run ID of the most recent workflow run
    run_id=$(gh run list --workflow "$workflow" --repo "$repo" --json 'databaseId' --jq '.[0].databaseId')
    echo "run_id: $run_id"
    gh run watch "$run_id" --repo "$repo" --interval $interval --exit-status
    if [[ $? -ne 0 ]]; then
        echo "workflow run $run_id failed"
        return 1
    fi

    # Extract PR number from the run log
    pr_number=$(gh run view "$run_id" --repo "$repo" --log | grep -o 'pull-request-number: [0-9]\+' | head -n 1 | sed 's/pull-request-number: //')
    if [[ -z "$pr_number" ]]; then
        echo "No pr is created, assume it's merged"
        return 0
    fi
    echo "PR number: $pr_number"


    # Wait for PR to be merged
    start_time=$(date +%s)
    while [[ $(($(date +%s) - start_time)) -lt $timeout ]]; do
        pr_status=$(gh pr view "$pr_number" --repo "$repo" --json 'state' --jq '.state')
        if [[ $pr_status == "MERGED" ]]; then
            echo "PR number $pr_number is merged"
            return 0
        fi
        sleep "$interval"
    done

    echo "Timeout waiting for PR $pr_number to be merged"
    return 1
}

function wait_for_services_ready() {
    set +e # Ignore error when kubectl command fails

    local -n services="$1"
    local timeout="${JOB_TIMEOUT:-600}"  # 10 mins
    local interval="${JOB_CHECK_INTERVAL:-10}"

    echo "waiting for services ready"

    start_time=$(date +%s)
    while [[ $(($(date +%s) - $start_time)) -lt $timeout ]]; do
        all_ready=true
        for svc in "${!services[@]}"; do
            if [[ ${services[$svc]} == "true" ]]; then
                continue
            else
                all_ready=false
            fi

            ready=$(kubectl get ${svc} -ojsonpath='{.status.readyReplicas}' 2>/dev/null)
            if [[ $? -eq 0 ]]; then
                if [[ $ready -ge 1 ]]; then
                    services[$svc]="true"
                    echo "Service $svc is ready"
                fi
            fi
        done

        if $all_ready; then
            echo "All services ready!"
            return 0
        else
            sleep "$interval"
        fi
    done

    # Report unready services
    echo "Following services are unready:"
    for svc in "${!services[@]}"; do
        if [[ ${services[$svc]} == "false" ]]; then
            echo $svc
        fi
    done
    return 1
}

function get_blob_file_path() {
    local blob_url=$1
    echo "$blob_url" | sed -E 's|https://[a-zA-Z0-9-]+\.blob\.core\.windows\.net/[a-zA-Z0-9-]+/?(.*)|\1|'
}

function get_blob_container() {
    local blob_url=$1
    echo "$blob_url" | sed -E 's|https://[a-zA-Z0-9-]+\.blob\.core\.windows\.net/([a-zA-Z0-9-]+)/?.*|\1|'
}

function get_blob_storage_account() {
    local blob_url=$1
    echo "$blob_url" | sed -E 's|https://([a-zA-Z0-9-]+)\.blob\.core\.windows\.net.*|\1|'
}

function download_blob() {
    local blob_url=$1
    local local_file=$2
    local storage_account=$(get_blob_storage_account "$blob_url")
    local container=$(get_blob_container "$blob_url")
    local file_path=$(get_blob_file_path "$blob_url")
    az storage blob download \
        --only-show-errors --output none --no-progress \
        --account-name "${storage_account}" --container-name "$container" \
        --name "$file_path" --file "${local_file}"
}

function upload_blob() {
    local local_file=$1
    local blob_url=$2
    shift 2
    
    local storage_account=$(get_blob_storage_account "$blob_url")
    local container=$(get_blob_container "$blob_url")
    local file_path=$(get_blob_file_path "$blob_url")
    az storage blob upload \
        --only-show-errors --output none --no-progress \
        --account-name "${storage_account}" --container-name "$container" \
        --name "$file_path" --file "${local_file}" "$@"
}


function azureLogin() {
    local tenant_id=$1
    local client_id=$2
    local id_token=$(curl -H "Authorization: Bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" "${ACTIONS_ID_TOKEN_REQUEST_URL}" | yq -r '.value')
    az login --federated-token $id_token --service-principal -u $client_id -t $tenant_id
}

function enableAppGw() {
  set +e # ignore error
  local aks_name=$1
  local aks_rg=$2
  local appgwId=$3
  output=$(az aks enable-addons --name $aks_name --resource-group $aks_rg --addon ingress-appgw --appgw-id $appgwId 2>&1)
  if [[ $? -ne 0  && "$output" != *"ingress-appgw addon is already enabled"* ]]; then
    echo "Failed to enable AGIC for AKS cluster $aks_name"
    echo $output
    set -e
    return 1
  fi
  set -e
  return 0
}

function addAADGroupMember() {
    set +e
    group=$1
    member=$2
    output=$(az ad group member add --group "${group}" --member-id $member 2>&1)
    if [[ $? -ne 0 && "$output" != *"One or more added object references already exist"* ]]; then
        echo "Failed to add member $member to group $group, error: $output"
        set -e
        return 1
    fi
    set -e
    return 0
}


function removeAADGroupMember() {
    set +e
    group=$1
    member=$2
    output=$(az ad group member remove --group "${group}" --member-id $member 2>&1)
    if [[ $? -ne 0 && "$output" != *"does not exist or one of its queried reference-property objects are not present"* ]]; then
        echo "Failed to add member $member to group $group, error: $output"
        set -e
        return 1
    fi
    set -e
    return 0
}