#!/usr/bin/env bash

set -o pipefail

had_error=0
VERSION="2.0.0"

project="augustus"
branch=""
job_name="linux_release_d"   #Outputs stellaris_RD
SSH_TEST_HOST="gitlab.build.paradox-interactive.com"
RECOMMENDED_PYTHON="3.10.0"
friendly="${RECOMMENDED_PYTHON%.0}"
export VAULT_ADDR="https://vault.internal.paradox-interactive.com"

usage() {
  cat <<'EOF'
Usage: get_exe_linux.sh [--project <name>] [--branch <name>] [--job <name>]
                        [--project-override <name>] [--branch-override <name>] [--job-name-override <name>]
EOF
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --project|--project-override)
      project="${2:-}"
      shift 2
      ;;
    --branch|--branch-override)
      branch="${2:-}"
      shift 2
      ;;
    --job|--job-name-override|--job-override)
      job_name="${2:-}"
      shift 2
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "Unknown argument: $1"
      usage
      exit 1
      ;;
  esac
done

Log() {
  local level="$1"
  shift
  local ts msg color reset
  ts="$(date "+%Y-%m-%d %H:%M:%S")"
  msg="$*"

  if command -v tput >/dev/null 2>&1; then
    case "$level" in
      OK) color="$(tput setaf 2)" ;;
      WARN) color="$(tput setaf 3)" ;;
      ERROR) color="$(tput setaf 1)" ;;
      INFO|*) color="$(tput setaf 7)" ;;
    esac
    reset="$(tput sgr0)"
    echo "${color}${ts} [${level}]  - ${msg}${reset}"
  else
    echo "${ts} [${level}]  - ${msg}"
  fi
}

Fail() {
  Log ERROR "$1"
  had_error=1
  exit 1
}

PY_CMD=""
PY_REAL_PATH=""
PY_VERSION_STR=""
POETRY_EXE=""
branch_raw=""
branch_display=""
destination=""

Check_Authentication() {
  # Check that computer's on internal network and authenticated with GitLab
  if ! command -v ssh >/dev/null 2>&1; then
    Fail "SSH client not found in PATH. Please install an SSH client. Instructions here: https://paradoxinteractive.atlassian.net/wiki/spaces/PROG/pages/1681817613/BATMake+get_exe+setup+guide+-+Windows#Installing-SSH-Client"
  fi

  local ssh_output code
  ssh_output="$(ssh -T -o BatchMode=yes -o ConnectTimeout=5 -o StrictHostKeyChecking=accept-new "git@${SSH_TEST_HOST}" 2>&1)"
  code=$?

  if [[ $code -eq 0 ]]; then
    Log OK "Computer is authenticated with ${SSH_TEST_HOST} over SSH"
  elif [[ "${ssh_output}" == *"Permission denied"* ]]; then
    Fail "Authentication failed. Please authenticate your computer with GitLab. Instructions: https://paradoxinteractive.atlassian.net/wiki/spaces/PROG/pages/1681817613/BATMake+get_exe+setup+guide+-+Windows#GitLab-Authentication"
  elif [[ $code -eq 255 ]]; then
    Fail "Failed to contact ${SSH_TEST_HOST}. Please ensure that you're either connected to the VPN or to the office network."
  elif [[ $code -eq 1 ]]; then
    Log WARN "Contacted ${SSH_TEST_HOST}, but received exit 1 for banner-only auth (?)"
  else
    Fail "Connection test to ${SSH_TEST_HOST} returned exit ${code}. Aborting."
  fi
}

Check_Git() {
  # Check Git's installed. Check script is running in a Git repo.
  if ! command -v git >/dev/null 2>&1; then
    Fail "Git must be available via the commandline to run get_exe. Please install git. Instructions here: https://paradoxinteractive.atlassian.net/wiki/spaces/PROG/pages/1681817613/BATMake+get_exe+setup+guide+-+Windows#Git"
  fi

  if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
    Fail "It doesn't look like get_exe is running inside a Git repository. Get_exe must be run inside your game repo. Instructions for cloning your game repo and using get_exe here: https://paradoxinteractive.atlassian.net/wiki/spaces/PROG/pages/1681817613/BATMake+get_exe+setup+guide+-+Windows"
  fi

  Log OK "Script is running inside Git repo at $(pwd)"
}

Check_Python() {
  # Find Python binary, get version, compare version to requirement
  local py_cmd
  py_cmd="$(command -v python || true)"
  if [[ -z "$py_cmd" ]]; then
    py_cmd="$(command -v py || true)"
  fi
  if [[ -z "$py_cmd" ]]; then
    py_cmd="$(command -v python3 || true)"
  fi
  if [[ -z "$py_cmd" ]]; then
    Fail "Python not found. Please install Python ${RECOMMENDED_PYTHON}. Instructions here: https://paradoxinteractive.atlassian.net/wiki/spaces/PROG/pages/1681817613#Installing-Python"
  fi

  PY_CMD="$py_cmd"
  PY_REAL_PATH="$("$PY_CMD" -c 'import sys, os; print(os.path.realpath(sys.executable))' 2>/dev/null | tr -d '\r' | tr -d '\n')"
  if [[ -n "$PY_REAL_PATH" ]]; then
    PY_CMD="$PY_REAL_PATH"
  fi

  PY_VERSION_STR="$("$PY_CMD" -c "import sys; print('.'.join(map(str, sys.version_info[:3])))" 2>/dev/null | tr -d '\r' | tr -d '\n')"
  if [[ -z "$PY_VERSION_STR" ]]; then
    Fail "Could not determine Python version."
  fi

  version_ge "$PY_VERSION_STR" "$RECOMMENDED_PYTHON"
  if [[ $? -eq 0 ]]; then
    Log OK "Found Python ${PY_VERSION_STR} at ${PY_REAL_PATH:-$PY_CMD}"
  else
    Fail "Found Python ${PY_VERSION_STR} at ${PY_REAL_PATH:-$PY_CMD}. Please uninstall ${PY_VERSION_STR}, and install Python ${friendly}. Instructions here: https://paradoxinteractive.atlassian.net/wiki/spaces/PROG/pages/1681817613/BATMake+get_exe+setup+guide+-+Windows#Intro.4"
  fi
}

version_ge() {
  local a b i
  IFS='.' read -r -a a <<<"$1"
  IFS='.' read -r -a b <<<"$2"
  for i in 0 1 2; do
    local av="${a[$i]:-0}"
    local bv="${b[$i]:-0}"
    if (( av > bv )); then
      return 0
    elif (( av < bv )); then
      return 1
    fi
  done
  return 0
}

Ensure_Poetry() {
  # Check Poetry's installed. Attempt to install via default python binary's pip if not present.
  local p
  p="$(command -v poetry || true)"
  if [[ -n "$p" ]]; then
    POETRY_EXE="$p"
    local ver
    ver="$("$POETRY_EXE" --version 2>/dev/null | tr -d '\r' | tr -d '\n')"
    Log OK "Found ${ver} at ${POETRY_EXE}"
    return
  fi

  Log INFO "Poetry not found on PATH - installing latest via pip."
  "$PY_CMD" -m pip install -U poetry
  local exit_code=$?
  if [[ $exit_code -ne 0 ]]; then
    Fail "pip install -U poetry failed with exit code ${exit_code}"
  else
    Log OK "Poetry installed successfully."
  fi

  p="$(command -v poetry || true)"
  if [[ -n "$p" ]]; then
    POETRY_EXE="$p"
    local ver
    ver="$("$POETRY_EXE" --version 2>/dev/null | tr -d '\r' | tr -d '\n')"
    Log OK "Poetry ${ver} found at ${POETRY_EXE}"
  else
    Log ERROR "Poetry still not found. Please ensure that your Python scripts folder is on the PATH"
    local user_scripts
    user_scripts="$("$PY_CMD" -c 'import site, os; print(os.path.join(site.USER_BASE, "bin"))' 2>/dev/null | tr -d '\r' | tr -d '\n')"
    if [[ -n "$user_scripts" ]]; then
      Log INFO "Hint: Your python scripts folder appears to be '${user_scripts}'"
    fi
  fi
}

Poetry_Sync() {
  if [[ -n "$POETRY_EXE" ]]; then
    "$POETRY_EXE" sync
    local exit_code=$?
    if [[ $exit_code -ne 0 ]]; then
      Fail "Poetry sync failed with exit code ${exit_code}"
    else
      Log OK "Poetry sync completed"
    fi
  else
    Fail "Poetry not found."
  fi
}

Resolve_Project_Details() {
  # Find project, branch, and correct binary location.
  if [[ -z "$project" ]]; then
    local url leaf
    url="$(git remote -v | awk '/\(fetch\)/ {print $2; exit}')"
    leaf="$(basename "${url}")"
    project="${leaf%.git}"
  else
    Log INFO "Project set to '${project}' by provided parameter"
  fi

  if [[ -n "$branch" ]]; then
    branch_raw="$branch"
    Log INFO "Overriding branch to '${branch}'"
  else
    branch_raw="$(git symbolic-ref --short HEAD 2>/dev/null | tr -d '\r' | tr -d '\n')"
  fi

  branch="${branch_raw//\//%2f}"
  branch_display="$branch_raw"

  destination="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
}

finalize() {
  if [[ $had_error -eq 1 ]]; then
    echo
    Log ERROR "Get_exe has encountered an error. Please read the logs and associated instructions. If needed, reach out to your RE or us at #cts_bat_support."
  else
    echo
    Log OK "Binary updated."
  fi
  echo "Press Enter to close this window..."
  read -r
}

trap finalize EXIT

Log INFO "Running GetExe $VERSION (Linux)"
Log INFO "Checking if your computer's authenticated with GitLab..."
Check_Authentication
Log INFO "Checking Git repo..."
Check_Git
Log INFO "Checking for Python..."
Check_Python
Log INFO "Checking for Poetry..."
Ensure_Poetry
Log INFO "Syncing with BATMake requirements..."
Poetry_Sync
Log INFO "Resolving project details..."
Resolve_Project_Details

build_key="${project}-${job_name}-${branch}"
Log OK "Project: ${project} / Branch: ${branch} / Job: ${job_name} = Build key: ${build_key}"

Log INFO "Updating binary..."
if [[ -n "$POETRY_EXE" ]]; then
  "$POETRY_EXE" run batmake archive.pull \
    --project-name "$project" \
    --buildsync-key "$build_key" \
    --destination "$destination"
else
  poetry run batmake archive.pull \
    --project-name "$project" \
    --buildsync-key "$build_key" \
    --destination "$destination"
fi

exit_code=$?
if [[ $exit_code -ne 0 ]]; then
  Fail "batmake archive.pull failed with exit code ${exit_code}"
fi
