#!/bin/bash
set -euo pipefail

SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"
BUILD_DIR="${SCRIPTPATH}/../build"
BUILD_ID=$(uuidgen | cut -d'-' -f1 | tr '[:upper:]' '[:lower:]')

TAP_REPO="aws/homebrew-tap"
TAP_NAME=$(echo ${TAP_REPO} | cut -d'/' -f2)

SYNC_DIR="${BUILD_DIR}/homebrew-sync"
FORK_DIR="${SYNC_DIR}/${TAP_NAME}"
DOWNLOAD_DIR="${BUILD_DIR}/downloads"
BREW_CONFIG_DIR="${BUILD_DIR}/brew-config"

REPO=$(make -s -f "${SCRIPTPATH}/../Makefile" repo-full-name)
BINARY_BASE=""
PLATFORMS=("darwin/amd64" "linux/amd64")
DRY_RUN=0

GH_CLI_VERSION="0.10.1"
GH_CLI_CONFIG_PATH="${HOME}/.config/gh/config.yml"
KERNEL=$(uname -s | tr '[:upper:]' '[:lower:]')
OS="${KERNEL}"
if [[ "${KERNEL}" == "darwin" ]]; then 
  OS="macOS"
fi

VERSION_REGEX="^v[0-9]+\.[0-9]+\.[0-9]+\$"
VERSION=$(make -s -f "${SCRIPTPATH}/../Makefile" version)

USAGE=$(cat << EOM
  Usage: sync-to-aws-homebrew-tap  -r <repo> -b <binary-basename> -p <platform_pairs>
  Syncs tar.gz\'d binaries to the aws/homebrew-tap

  Example: sync-to-aws-homebrew-tap -r "aws/amazon-ec2-instance-selector"
          Required:
            -b          Binary basename (i.e. -b "ec2-instance-selector")

          Optional:
            -r          Github repo to sync to in the form of "org/name"  (i.e. -r "aws/amazon-ec2-instance-selector") [DEFAULT: output of \`make repo-full-name\`]
            -v          VERSION: The application version of the docker image [DEFAULT: output of \`make version\`]
            -p          Platform pair list (os/architecture) [DEFAULT: linux/amd64]
            -d          Dry-Run will do all steps except pushing to git and opening the sync PR
EOM
)

# Process our input arguments
while getopts "p:b:r:v:d" opt; do
  case ${opt} in
    r ) # Github repo
        REPO="$OPTARG"
      ;;
    b ) # binary basename
        BINARY_BASE="$OPTARG"
      ;;
    p ) # Supported Platforms
        IFS=',' read -ra PLATFORMS <<< "$OPTARG"
      ;;
    v ) # App Version
        VERSION="$OPTARG"
      ;;
    d ) # Dry Run
        DRY_RUN=1
      ;;
    \? )
        echo "$USAGE" 1>&2
        exit
      ;;
  esac
done

if [[ -z "${BINARY_BASE}" ]]; then 
  echo "Binary Basename (-b) must be specified"
  exit 3
fi

if [[ ! "${VERSION}" =~ $VERSION_REGEX ]]; then
  echo "🙈 Not on a current release, so not syncing with tap $TAP_REPO"
  exit 3
fi

if [[ -z "${REPO}" ]]; then 
  echo "Repo (-r) must be specified if no \"make repo-full-name\" target exists"
fi

if [[ -z $(command -v gh) ]] || [[ ! $(gh --version) =~ $GH_CLI_VERSION ]]; then
  mkdir -p ${BUILD_DIR}/gh
  curl -Lo ${BUILD_DIR}/gh/gh.tar.gz "https://github.com/cli/cli/releases/download/v${GH_CLI_VERSION}/gh_${GH_CLI_VERSION}_${OS}_amd64.tar.gz"
  tar -C ${BUILD_DIR}/gh -xvf "${BUILD_DIR}/gh/gh.tar.gz"
  export PATH="${BUILD_DIR}/gh/gh_${GH_CLI_VERSION}_${OS}_amd64/bin:$PATH"
  if [[ ! $(gh --version) =~ $GH_CLI_VERSION ]]; then
    echo "❌ Failed install of github cli"
    exit 4
  fi
fi

function restore_gh_config() {
  mv -f "${GH_CLI_CONFIG_PATH}.bkup" "${GH_CLI_CONFIG_PATH}" || :
}

if [[ -n $(env | grep GITHUB_TOKEN) ]] && [[ -n "${GITHUB_TOKEN}" ]]; then
  trap restore_gh_config EXIT INT TERM ERR
  mkdir -p "${HOME}/.config/gh"
  cp -f "${GH_CLI_CONFIG_PATH}" "${GH_CLI_CONFIG_PATH}.bkup" || :
  cat << EOF > "${GH_CLI_CONFIG_PATH}"
hosts:
    github.com:
        oauth_token: ${GITHUB_TOKEN}
        user: ${GITHUB_USERNAME}
EOF
fi

VERSION_NUM=$(echo "${VERSION}" | cut -c 2- | tr -d '\n')

function fail() {
  echo "❌ Homebrew sync failed"
  exit 5
}

trap fail ERR TERM INT

rm -rf "${DOWNLOAD_DIR}" "${SYNC_DIR}" "${BREW_CONFIG_DIR}"
mkdir -p "${DOWNLOAD_DIR}" "${SYNC_DIR}" "${BREW_CONFIG_DIR}"

BASE_ASSET_URL="https://github.com/${REPO}/releases/download/${VERSION}/${BINARY_BASE}"
MAC_HASH=""
MAC_ARM64_HASH=""
LINUX_HASH=""
LINUX_ARM64_HASH=""

function hash_file() {
  local file="${1}"
  echo "$(openssl dgst -sha256 "${file}" | cut -d' ' -f2 | tr -d '\n')"
}

for os_arch in "${PLATFORMS[@]}"; do
    os=$(echo "${os_arch}" | cut -d'/' -f1)
    arch=$(echo "${os_arch}" | cut -d'/' -f2)

    ## Windows is not supported with homebrew
    if [[ "${os}" == "windows" ]]; then 
      continue
    fi

    asset_url="${BASE_ASSET_URL}-${os}-${arch}.tar.gz"
    asset_file="${BINARY_BASE}-${os}-${arch}.tar.gz"
    asset_file_path="${DOWNLOAD_DIR}/${asset_file}"

    curl -H 'Cache-Control: no-cache' -Lo "${asset_file_path}" "${asset_url}?$(date +%s)"

    asset_file_size=$(du -k "${asset_file_path}" | cut -f1)
    if [[ "${asset_file_size}" -lt 100 ]]; then
      ## If we cannot download and dry-run is set, build it locally
      if [[ "${DRY_RUN}" -eq 1 ]]; then 
        ${SCRIPTPATH}/build-binaries -d -v "${VERSION}" -p "${os_arch}"
        cp "${BUILD_DIR}/bin/${asset_file}" ${asset_file_path}
      else 
        echo "❗️${asset_file_path} is empty, skipping"
        continue
      fi
    fi

    if [[ "${os}" == "darwin" && "${arch}" == "amd64" ]]; then
      MAC_HASH=$(hash_file "${asset_file_path}")
    elif [[ "${os}" == "darwin" && "${arch}" == "arm64" ]]; then
      MAC_ARM64_HASH=$(hash_file "${asset_file_path}")
    elif [[ "${os}" == "linux" && "${arch}" == "amd64" ]]; then
      LINUX_HASH=$(hash_file "${asset_file_path}")
    elif [[ "${os}" == "linux" && "${arch}" == "arm64" ]]; then
      LINUX_ARM64_HASH=$(hash_file "${asset_file_path}")
    fi

done

cat << EOM > "${BREW_CONFIG_DIR}/${BINARY_BASE}.json"
{
    "name": "${BINARY_BASE}",
    "version": "${VERSION_NUM}",
    "bin": "${BINARY_BASE}",
    "bottle": {
        "root_url": "${BASE_ASSET_URL}",
        "sha256": {
            "arm64_big_sur": "${MAC_ARM64_HASH}",
            "sierra": "${MAC_HASH}",
            "linux": "${LINUX_HASH}",
            "linux_arm": "${LINUX_ARM64_HASH}"
        }
    }
}
EOM

if [[ "${DRY_RUN}" -eq 0 ]]; then 
  if [[ -z "${MAC_HASH}" ]] && [[ -z "${MAC_ARM64_HASH}" ]] && [[ -z "${LINUX_HASH}" ]] && [[ -z "${LINUX_ARM64_HASH}" ]]; then 
    echo "❌ No hashes were calculated and dry-run is NOT engaged. Bailing out so we don't open a bad PR to the tap."
    exit 4
  fi
  cd "${SYNC_DIR}"
  gh repo fork $TAP_REPO --clone --remote
  cd "${FORK_DIR}"
  git remote set-url origin https://${GITHUB_USERNAME}:${GITHUB_TOKEN}@github.com/${GITHUB_USERNAME}/${TAP_NAME}.git
  DEFAULT_BRANCH=$(git rev-parse --abbrev-ref HEAD | tr -d '\n')

  git config user.name "ec2-bot 🤖"
  git config user.email "ec2-bot@users.noreply.github.com"
  
  # Sync the fork
  git pull upstream "${DEFAULT_BRANCH}"
  git push -u origin "${DEFAULT_BRANCH}"

  FORK_RELEASE_BRANCH="${BINARY_BASE}-${VERSION}-${BUILD_ID}"
  git checkout -b "${FORK_RELEASE_BRANCH}" upstream/${DEFAULT_BRANCH}

  cp "${BREW_CONFIG_DIR}/${BINARY_BASE}.json" "${FORK_DIR}/bottle-configs/${BINARY_BASE}.json"
  
  git add "bottle-configs/${BINARY_BASE}.json"
  git commit -m "${BINARY_BASE} update to version ${VERSION_NUM}"

  RELEASE_ID=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
    https://api.github.com/repos/${REPO}/releases | \
    jq --arg VERSION "$VERSION" '.[] | select(.tag_name==$VERSION) | .id')
  
  RELEASE_NOTES=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" \
    https://api.github.com/repos/${REPO}/releases/${RELEASE_ID} | \
    jq -r '.body')

  PR_BODY=$(cat << EOM
  ## ${BINARY_BASE} ${VERSION} Automated Release! 🤖🤖

  ### Release Notes 📝:

  ${RELEASE_NOTES}
EOM
)

  git push -u origin "${FORK_RELEASE_BRANCH}"
  gh pr create --title "🥳 ${BINARY_BASE} ${VERSION} Automated Release! 🥑" \
    --body "${PR_BODY}"
fi

echo "✅ Homebrew sync complete"
