#!/usr/bin/env bash
# set -eo pipefail comment out for now because of a Harvester issue

SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
BASE_DIR="$(pwd)"

CYAN="\033[96m"
YELLOW="\033[93m"
RESET="\033[0m"
BOLD="\033[1m"
NORMAL="\033[22m"
CHECK="\xE2\x9C\x94"

PUSH=""
REGISTRY=""
REGISTRY_ORG=""
IMAGE_PREFIX="ui-extension-"
FORCE="false"
GITHUB_BUILD="true"
GITHUB_RELEASE_TAG=""
PODMAN_CONTAINER="false"
UPDATE_OLD_PACKAGES="true"
UPDATE_LATEST_PACAKGES="true"

GITHUB_SOURCE=$(git config --get remote.origin.url | sed -e 's/^git@.*:\([[:graph:]]*\).git/\1/')
GITHUB_BRANCH="main"

usage() {
  echo "Usage: $0 [<options>] [extensions]"
  echo " options:"
  echo "  -s <repo>    Specify destination GitHub repository (org/name) - defaults to the git origin"
  echo "  -b <branch>  Specify destination GitHub branch"
  echo "  -t <tag>     Specify the Github release tag to build when a release has been tagged and published"
  echo "  -f           Force building the chart even if it already exists"
  echo "  -c           Build as a container image rather than publishing to Github"
  echo "  -p           Push container images on build"
  echo "  -r <name>    Specify destination container registry for built images"
  echo "  -o <name>    Specify destination container registry organization for built images"
  echo "  -i <prefix>  Specify prefix for the built container image (default: 'ui-extension-')"
  echo "  -l           Specify Podman container build"
  echo "  -n           Do not check for updates to existing Charts (Chart.yaml)"
  echo "  -e           Only check for updates to existing Charts (Chart.yaml)"
  exit 1
}

while getopts "hvr:o:pi:fcb:t:s:lne" opt; do
  case $opt in
    h)
      usage
      ;;
    p)
      PUSH="--push"
      ;;
    r)
      REGISTRY="${OPTARG%/}/"
      ;;
    o)
      REGISTRY_ORG="${OPTARG}"
      ;;
    i)
      IMAGE_PREFIX="${OPTARG}"
      ;;
    f)
      FORCE="true"
      ;;      
    c)
      GITHUB_BUILD="false"
      ;;
    s)
      GITHUB_BUILD="true"
      GITHUB_SOURCE="${OPTARG}"
      ;;
    b)
      GITHUB_BUILD="true"
      GITHUB_BRANCH="${OPTARG}"
      ;;
    t)
      GITHUB_RELEASE_TAG="${OPTARG}"
      ;;
    l)
      PODMAN_CONTAINER="true"
      ;;
    n)
      UPDATE_OLD_PACKAGES="false"
      ;;
    e)
      UPDATE_OLD_PACKAGES="true"
      UPDATE_LATEST_PACAKGES="false"
      ;;
    *)
      usage
      ;;
  esac
done

shift $((OPTIND-1))

PLUGINS=( "$@" )
BUILT="false"

echo -e "${CYAN}${BOLD}Publishing UI Extensions${RESET}"

pushd ${BASE_DIR} > /dev/null

if [ "${GITHUB_BUILD}" == "true" ]; then
  # Determine if gh-pages build is possible
  if [[ "${GITHUB_BRANCH}" == "gh-pages" ]] && ! git show-ref -q gh-pages; then
    echo -e "${YELLOW}'gh-pages' branch not found, this branch must exist before running this script${RESET}"
    exit 1
  fi

  echo -e "${CYAN}GitHub Repository: ${GITHUB_SOURCE}${RESET}"
  echo -e "${CYAN}GitHub Branch    : ${GITHUB_BRANCH}${RESET}"

  if [[ -n "${GITHUB_RELEASE_TAG}" ]]; then
    echo -e "${CYAN}GitHub Release   : ${GITHUB_RELEASE_TAG}${RESET}"
  fi
else
  echo -e ${CYAN}"Image prefix: ${IMAGE_PREFIX}${RESET}"
fi

# --------------------------------------------------------------------------------
# Check that we have the required commands avaialble for this script
# --------------------------------------------------------------------------------

if ! [[ -f ${BASE_DIR}/package.json ]]; then
  echo -e "${YELLOW}You must run from the top-level folder${RESET}"
  exit 1
fi

# Check this is a Rancher extension
IS_SHELL=$(grep "\"@rancher/shell" package.json -c)

if [ "${IS_SHELL}" -ne 1 ]; then
  echo -e "${YELLOW}Current folder does not appear to contain Rancher Extensions${RESET}"
  exit 1
fi

if ! [[ -d ${BASE_DIR}/node_modules ]]; then
  echo -e "${YELLOW}You must run ${BOLD}yarn install${NORMAL} before running this script${RESET}"
  exit 1
fi

COMMANDS=("node" "jq" "yq" "git" "helm" "yarn")
if [ "${GITHUB_BUILD}" == "false" ]; then
  if [ "${PODMAN_CONTAINER}" == "true" ]; then
    COMMANDS+=("podman")
  else
    COMMANDS+=("docker")
  fi
fi

HAVE_COMMANDS="true"
for CMD in "${COMMANDS[@]}"
do
  if ! command -v ${CMD} >/dev/null; then
    echo -e "${YELLOW}This script requires ${BOLD}${CMD}${NORMAL} to be installed and on your PATH${RESET}"
    HAVE_COMMANDS="false"
  fi
done

if [ "${HAVE_COMMANDS}" == "false" ]; then
  exit 1
fi

# --------------------------------------------------------------------------------
# Only do container args checks if not GitHub publish
# --------------------------------------------------------------------------------
if [ "${GITHUB_BUILD}" == "false" ]; then
  BASE_EXT=$(jq -r .name ${BASE_DIR}/package.json)
  EXT_VERSION=$(jq -r .version ${BASE_DIR}/package.json)

  if [ -z ${EXT_VERSION} ]; then
    EXT_VERSION="0.0.0"
  fi

  if [[ -z ${REGISTRY_ORG} ]]; then
    # Infer that the user has the same Docker registry org as their GitHub org
    GITHUB_REPO=$(git config --get remote.origin.url | sed -e 's/^git@.*:\([[:graph:]]*\).git/\1/')
    REGISTRY_ORG=$(dirname ${GITHUB_REPO})
    echo -e "Inferring built images will reside in registry organization ${CYAN}${BOLD}${REGISTRY}${REGISTRY_ORG}${RESET} based on configured origin remote pointing to ${CYAN}${BOLD}${GITHUB_REPO}${RESET}"
  fi

  if [[ -z ${REGISTRY_ORG} ]]; then
    # Inferring from the git config still failed
    echo "Cannot build images without valid organization for Docker images. Unable to infer REGISTRY_ORG="
    exit 1
  fi

  if [ -n "${GITHUB_RELEASE_TAG}" ] && [[ ${GITHUB_RELEASE_TAG} != "${BASE_EXT}-${EXT_VERSION}" ]]; then
    echo -e "${YELLOW}Github tagged release name does not match ${RESET}${BOLD}${BASE_EXT}-${EXT_VERSION}${RESET}"
    echo -e "${YELLOW}Stopping build${RESET}"
    exit 1
  fi

  if [ "${PODMAN_CONTAINER}" == "false" ]; then
    docker images > /dev/null
    if [ $? -ne 0 ]; then
      echo "docker is not running - this is required to build container images for the UI Extensions"
      exit 1
    fi
  fi
fi

ASSETS=${BASE_DIR}/assets
CHARTS=${BASE_DIR}/charts
mkdir -p ${ASSETS}
mkdir -p ${CHARTS}

TMP=${BASE_DIR}/tmp
CHART_TMP=${BASE_DIR}/tmp/_charts
rm -rf ${TMP}
mkdir -p ${TMP}

# --------------------------------------------------------------------------------
# Copy the plugin server template into the temporary folder
# --------------------------------------------------------------------------------
pushd ${TMP} > /dev/null
cp -r ${SCRIPT_DIR}/helm .
popd > /dev/null

CHART_TEMPLATE=${BASE_DIR}/tmp/helm
ROOT_INDEX=${BASE_DIR}/index.yaml

# --------------------------------------------------------------------------------
# Iterate through all existing charts and look for updates/removals
# --------------------------------------------------------------------------------
if [ "${UPDATE_OLD_PACKAGES}" = "true" ]; then
  pushd ${ASSETS} > /dev/null
  echo -e "${CYAN}${BOLD}Checking existing charts for updates ...${RESET}"

  for FOLDER_NAME in */ ; do
    EXT_NAME=${FOLDER_NAME::${#FOLDER_NAME}-1}
    echo -e "${CYAN}${EXT_NAME}${RESET}"

    for CHART_ARCHIVE in ${EXT_NAME}/*.tgz ; do
      rm -f ${TMP}/Chart.yaml

      # path in chart may be different to tar file name, so extratct the Chart.yaml file to the top-level folder
      tar --strip-components=1 -C ${TMP} -xf ${CHART_ARCHIVE} */Chart.yaml

      EXISTING_MD5=$(md5 -q ${TMP}/Chart.yaml)
      VERSION=$(yq eval .version ${TMP}/Chart.yaml)

      CHART_FOLDER=${CHARTS}/${EXT_NAME}/${VERSION}
      LATEST=${CHART_FOLDER}/Chart.yaml

      if [ ! -f "${LATEST}" ]; then
        echo "  - Chart for ${EXT}-${VERSION} appears to have been deleted - removing chart archive: ${CHART_ARCHIVE}"
        rm -f ${ASSETS}/${CHART_ARCHIVE}
        BUILT="true"
      else
        # Re-package the helm chart so that the Chart.yaml is processed in the same way so we can compare it
        mkdir -p ${TMP}/tmp_chart
        helm package ${CHART_FOLDER} -d ${TMP}/tmp_chart > /dev/null
        rm ${TMP}/Chart.yaml

        # path in chart may be different to tar file name, so list the files to find what the chart archive is named
        FILENAME=$(cd ${TMP}/tmp_chart; ls)

        # path in chart may be different to tar file name, so extratct the Chart.yaml file to the top-level folder
        tar --strip-components=1 -C ${TMP} -xf ${TMP}/tmp_chart/${FILENAME} */Chart.yaml
        LATEST_MD5=$(md5 -q ${TMP}/Chart.yaml)

        rm -f $TMP/tmp_chart/${FILENAME}

        if [ "${EXISTING_MD5}" != "${LATEST_MD5}" ]; then
          BUILT="true"

          echo "  + Chart.yaml has changed for ${CHART_ARCHIVE}"
          # Chart was already re-generated - update ir
          rm ${CHART_ARCHIVE}
          helm package ${CHART_FOLDER} -d ${ASSETS}/${EXT_NAME}
        fi
      fi

      rm -d ${TMP}/tmp_chart
      rm ${TMP}/Chart.yaml
      
    done
  done

  popd > /dev/null
fi

# --------------------------------------------------------------------------------
# Iterate through all packages - built them all or build only those specified on the command line
# --------------------------------------------------------------------------------
if [ "${UPDATE_LATEST_PACAKGES}" = "true" ]; then
  for d in pkg/*/ ; do
    pkg=$(basename $d)

    if [ -z "$1" ] || [[ " ${PLUGINS[*]} " =~ " ${pkg} " ]]; then
      # Check we don't already have a published version by looking in the assets folder
      PKG_VERSION=$(jq -r .version ./pkg/${pkg}/package.json)
      PKG_NAME="${pkg}-${PKG_VERSION}"
      PKG_ASSET=${ASSETS}/${pkg}/${PKG_NAME}.tgz

      # Skip the build for a package that does not match the tagged release name
      if [[ -n "${GITHUB_RELEASE_TAG}" ]] && [ ${GITHUB_BUILD} == "true" ] && [[ ${GITHUB_RELEASE_TAG} != ${PKG_NAME} ]]; then
        echo -e "${YELLOW}Github release tag ${RESET}${BOLD}${GITHUB_RELEASE_TAG}${RESET}${YELLOW} does not match asset name${RESET}"
        echo -e "${YELLOW}Skipping ${RESET}${BOLD}${PKG_NAME}${RESET}"
        continue
      fi

      echo -e "${CYAN}${BOLD}Building extension: ${pkg} (${PKG_VERSION}) ${RESET}"

      echo "Package version: ${PKG_VERSION}"
      echo "Package folder:  ${PKG_NAME}"

      # --------------------------------------------------------------------------------
      # Build the plugin from source
      # --------------------------------------------------------------------------------
      echo -e "${CYAN}Building extension from source code${RESET}"
      FORCE_COLOR=1 yarn build-pkg $pkg | cat

      echo -e "${CYAN}Adding extension code ...${RESET}"

      EXT_FOLDER=${BASE_DIR}/extensions/${pkg}/${PKG_VERSION}
      PKG_DIST="${BASE_DIR}/dist-pkg/${PKG_NAME}"

      rm -rf ${EXT_FOLDER}

      mkdir -p ${EXT_FOLDER}/plugin

      # Copy the code into the folder
      cp -R ${PKG_DIST}/* ${EXT_FOLDER}/plugin

      pushd ${BASE_DIR}/extensions/${pkg}/${PKG_VERSION} > /dev/null
      rm -f plugin/report.html
      find plugin -type f | sort > files.txt
      popd > /dev/null

      # --------------------------------------------------------------------------------
      # Package extensions into tgz for the compressedEndpoint
      # --------------------------------------------------------------------------------
      echo -e "${CYAN}Packaging extension into tgz${RESET}"
      tar -czf ${BASE_DIR}/extensions/${pkg}/${PKG_VERSION}.tgz -C ${BASE_DIR}/extensions/${pkg} ${PKG_VERSION}

      # --------------------------------------------------------------------------------
      # Create the Helm chart
      # --------------------------------------------------------------------------------

      if [ -f ${PKG_ASSET} ] && [ "${FORCE}" == "false" ]; then
        echo -e "${YELLOW}Helm chart has already been created - skipping (run with -f to force build)${RESET}"
        continue;
      fi

      CHART_FOLDER=${CHARTS}/${pkg}/${PKG_VERSION}

      mkdir -p ${ASSETS}/${pkg}
      rm -rf ${CHART_FOLDER}
      mkdir -p ${CHART_FOLDER}

      cp -R ${CHART_TEMPLATE}/charts/ui-plugin-server/* ${CHART_FOLDER}

      # Update Chart.yaml and values.yaml from the package file metadata
      # Use the script from the template repository
      echo -e "${CYAN}Patching Helm chart template${RESET}"

      CHART=${CHART_FOLDER} REGISTRY="${REGISTRY}" ORG="${REGISTRY_ORG}" PACKAGE_JSON=${BASE_DIR}/pkg/${pkg}/package.json ${CHART_TEMPLATE}/scripts/patch

      # Copy README file from the plugin to the Helm chart, if there is one
      if [ -f "./pkg/${pkg}/README.md" ]; then
        cp ./pkg/${pkg}/README.md ${CHART_FOLDER}/README.md
      fi

      export GITHUB_BUILD
      export IMAGE_PREFIX
      export BASE_EXT
      export GITHUB_SOURCE
      export GITHUB_BRANCH

      # Additional patches
      ${SCRIPT_DIR}/helmpatch ${CHART_FOLDER} "${BASE_DIR}/pkg/${pkg}/package.json"

      # Package into a .tgz helm chart
      helm package ${CHART_FOLDER} -d ${ASSETS}/${pkg}

      BUILT="true"
    fi
  done
fi

# Update the Helm Index for all charts, if changes were made
if [ "${BUILT}" == "true" ]; then
  # --------------------------------------------------------------------------------
  # Update the helm index for all charts
  # --------------------------------------------------------------------------------
  HELM_INDEX=${BASE_DIR}/index.yaml

  echo "Updating Helm Index file"

  if [ -f "${HELM_INDEX}" ]; then
    UPDATE="--merge ${HELM_INDEX}"
  elif [ "${GITHUB_BUILD}" == "true" ] && [[ -n ${GITHUB_SOURCE} ]]; then
    # Check if git branch contains index.yaml
    GITHUB_SOURCE=$(echo -e "${GITHUB_SOURCE}" | sed 's/https:\/\///g')

    wget -P ${BASE_DIR} https://raw.githubusercontent.com/${GITHUB_SOURCE}/${GITHUB_BRANCH}/index.yaml 2>/dev/null
    HELM_INDEX="${BASE_DIR}/index.yaml"

    if [ -f "${HELM_INDEX}" ]; then
      UPDATE="--merge ${HELM_INDEX}"
    fi
  fi

  # Base URL referencing assets directly from GitHub
  BASE_URL="assets/"

  # Relative URL references assets within the container deployment
  RELATIVE_URL="plugin/"
  
  if [ "${GITHUB_BUILD}" == "true" ]; then
    helm repo index ${ASSETS} --url ${BASE_URL} ${UPDATE}
  elif ! [ -e "${HELM_INDEX}" ]; then
    helm repo index ${ASSETS} --url ${RELATIVE_URL}
  fi
fi

if [ "${GITHUB_BUILD}" == "true" ] && [[ -n "${GITHUB_RELEASE_TAG}" ]] && [ "${BUILT}" == "false" ]; then
  echo -e "${YELLOW}Github release tag ${RESET}${BOLD}${GITHUB_RELEASE_TAG}${RESET}${YELLOW} did not match any package name.${RESET}"
  echo -e "${YELLOW}Stopping build${RESET}"

  rm -rf ${CHART_TMP}
  rm -rf ${TMP} 
  exit 1
fi

if [ -f ${ROOT_INDEX} ] && [ "${GITHUB_BUILD}" == "false" ]; then
  UPDATE="--merge ${ROOT_INDEX}"
  helm repo index ${ASSETS} ${UPDATE}
fi

if [ -f ${ASSETS}/index.yaml ] && ! [ -e "${ROOT_INDEX}" ]; then
  cp ${ASSETS}/index.yaml ${BASE_DIR}
fi

if [ "${GITHUB_BUILD}" == "false" ]; then
  echo -e "${CYAN}Base extension: ${BASE_EXT}${RESET}"
  echo -e "${CYAN}Extension version: ${EXT_VERSION}${RESET}"

  # Build the container image
  ${SCRIPT_DIR}/bundle "${BASE_EXT}" "${EXT_VERSION}" "${REGISTRY}" "${REGISTRY_ORG}" "${IMAGE_PREFIX}" "${PUSH}" "${PODMAN_CONTAINER}"
else
  rm -rf ${CHART_TEMPLATE}
fi

if [ "${GITHUB_BUILD}" == "true" ] && [ -f ${ROOT_INDEX} ]; then
  if [[ -n "${GITHUB_RELEASE_TAG}" ]] && [ -f ${ASSETS}/index.yaml ]; then
    cp ${ASSETS}/index.yaml tmp
  else
    cp ${ROOT_INDEX} tmp
  fi
fi

if [ "${GITHUB_BUILD}" == "true" ] && [ "${BUILT}" == "true" ]; then
  echo -e "${BOLD}${CYAN}Packaging for Github Build${RESET}"
  # Make temp directory for workflow build artifact
  mkdir -p tmp/{assets,charts,extensions}

  cp -r ${ASSETS}/* tmp/assets
  cp -r ${CHARTS}/* tmp/charts
  cp -r ${BASE_DIR}/extensions/* tmp/extensions
fi

if [ "${BUILT}" == "true" ]; then
  echo -e "${CYAN}${BOLD}${CHECK} One or more packages built${RESET}"
fi

# Clean up
rm -rf ${CHART_TMP}

if [ "${GITHUB_BUILD}" == "false" ]; then
  rm -rf ${TMP} ${ASSETS} ${CHARTS} ${BASE_DIR}/extensions ${BASE_DIR}/dist-pkg ${ROOT_INDEX}
fi
