#!/usr/bin/env bash
set -euo pipefail

REPO="${DISPATCH_INSTALL_REPO:-nicholasoxford/dispatch}"
VERSION="${DISPATCH_VERSION:-latest}"
CHANNEL="${DISPATCH_CHANNEL:-stable}"
REQUESTED_INSTALL_DIR="${DISPATCH_INSTALL_DIR:-}"
DOWNLOAD_BASE_URL="${DISPATCH_DOWNLOAD_BASE_URL:-https://get.dispatchjoin.com/releases}"

require_cmd() {
  if ! command -v "$1" >/dev/null 2>&1; then
    echo "Missing required command: $1" >&2
    exit 1
  fi
}

detect_target() {
  local os arch
  os="$(uname -s)"
  arch="$(uname -m)"

  case "${os}" in
    Darwin)
      case "${arch}" in
        arm64) echo "aarch64-apple-darwin" ;;
        x86_64) echo "x86_64-apple-darwin" ;;
        *) return 1 ;;
      esac
      ;;
    Linux)
      # Prefer musl builds on Alpine/musl systems for compatibility.
      local libc_flavor
      libc_flavor="gnu"
      if command -v ldd >/dev/null 2>&1 && ldd --version 2>&1 | grep -qi musl; then
        libc_flavor="musl"
      fi
      case "${arch}" in
        x86_64)
          if [[ "${libc_flavor}" == "musl" ]]; then
            echo "x86_64-unknown-linux-musl"
          else
            echo "x86_64-unknown-linux-gnu"
          fi
          ;;
        aarch64|arm64)
          # We currently publish aarch64 GNU builds. Alpine arm64 users may require manual install.
          echo "aarch64-unknown-linux-gnu"
          ;;
        *) return 1 ;;
      esac
      ;;
    *)
      return 1
      ;;
  esac
}

github_get() {
  local url="$1"
  if [[ -n "${GITHUB_TOKEN:-}" ]]; then
    curl -fsSL -H "Authorization: Bearer ${GITHUB_TOKEN}" "${url}"
  else
    curl -fsSL "${url}"
  fi
}

sha256_file() {
  local file="$1"
  if command -v sha256sum >/dev/null 2>&1; then
    sha256sum "${file}" | awk '{print $1}'
  else
    shasum -a 256 "${file}" | awk '{print $1}'
  fi
}

normalize_channel() {
  local value
  value="$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]')"
  case "${value}" in
    stable|"")
      echo "stable"
      ;;
    beta|pre|prerelease)
      echo "beta"
      ;;
    *)
      echo "Unsupported DISPATCH_CHANNEL: ${1}. Use stable or beta." >&2
      exit 1
      ;;
  esac
}

resolve_release_json() {
  if [[ "${VERSION}" == "latest" ]]; then
    if [[ "${CHANNEL}" == "beta" ]]; then
      local releases_json prerelease_release
      releases_json="$(github_get "https://api.github.com/repos/${REPO}/releases?per_page=50")"
      prerelease_release="$(jq -c 'map(select(.prerelease == true and .draft == false)) | .[0] // empty' <<<"${releases_json}")"
      if [[ -z "${prerelease_release}" ]]; then
        echo "No beta release found for ${REPO}" >&2
        exit 1
      fi
      printf '%s\n' "${prerelease_release}"
    else
      github_get "https://api.github.com/repos/${REPO}/releases/latest"
    fi
  else
    github_get "https://api.github.com/repos/${REPO}/releases/tags/${VERSION}"
  fi
}

choose_install_dir() {
  if [[ -n "${REQUESTED_INSTALL_DIR}" ]]; then
    echo "${REQUESTED_INSTALL_DIR}"
    return
  fi

  if [[ -w "/usr/local/bin" ]]; then
    echo "/usr/local/bin"
  else
    echo "${HOME}/.local/bin"
  fi
}

install_binary() {
  local src="$1"
  local dir="$2"
  mkdir -p "${dir}"
  install -m 0755 "${src}" "${dir}/dispatch"
}

require_cmd curl
require_cmd jq
require_cmd tar
if ! command -v sha256sum >/dev/null 2>&1 && ! command -v shasum >/dev/null 2>&1; then
  echo "Missing required command: sha256sum or shasum" >&2
  exit 1
fi

CHANNEL="$(normalize_channel "${CHANNEL}")"

TARGET="$(detect_target || true)"
if [[ -z "${TARGET}" ]]; then
  echo "Unsupported platform: $(uname -s)/$(uname -m)" >&2
  exit 1
fi

ASSET_NAME="dispatch_${TARGET}.tar.gz"

ASSET_URL=""
CHECKSUMS_URL=""
RELEASE_TAG=""

if [[ -n "${DOWNLOAD_BASE_URL}" ]]; then
  DOWNLOAD_BASE_URL="${DOWNLOAD_BASE_URL%/}"
  echo "==> Resolving release metadata from ${DOWNLOAD_BASE_URL}"
  if [[ "${VERSION}" == "latest" ]]; then
    LATEST_POINTER="LATEST"
    if [[ "${CHANNEL}" == "beta" ]]; then
      LATEST_POINTER="BETA_LATEST"
    fi
    RELEASE_TAG="$(curl -fsSL "${DOWNLOAD_BASE_URL}/${LATEST_POINTER}" | tr -d '\r\n')"
  else
    RELEASE_TAG="${VERSION}"
  fi
  if [[ -z "${RELEASE_TAG}" ]]; then
    echo "Unable to resolve release tag from ${DOWNLOAD_BASE_URL}" >&2
    exit 1
  fi
  ASSET_URL="${DOWNLOAD_BASE_URL}/${RELEASE_TAG}/${ASSET_NAME}"
  CHECKSUMS_URL="${DOWNLOAD_BASE_URL}/${RELEASE_TAG}/dispatch_checksums.txt"
else
  echo "==> Resolving release metadata from GitHub"
  RELEASE_JSON="$(resolve_release_json)"
  RELEASE_TAG="$(jq -r '.tag_name // empty' <<<"${RELEASE_JSON}")"
  if [[ -z "${RELEASE_TAG}" ]]; then
    echo "Unable to resolve release tag for ${REPO}" >&2
    exit 1
  fi

  ASSET_URL="$(jq -r --arg name "${ASSET_NAME}" '.assets[]? | select(.name == $name) | .browser_download_url' <<<"${RELEASE_JSON}" | head -n1)"
  CHECKSUMS_URL="$(jq -r '.assets[]? | select(.name == "dispatch_checksums.txt") | .browser_download_url' <<<"${RELEASE_JSON}" | head -n1)"

  if [[ -z "${ASSET_URL}" ]]; then
    echo "Release ${RELEASE_TAG} does not contain ${ASSET_NAME}" >&2
    echo "Available assets:" >&2
    jq -r '.assets[]?.name' <<<"${RELEASE_JSON}" >&2
    exit 1
  fi
fi

TMP_DIR="$(mktemp -d)"
trap 'rm -rf "${TMP_DIR}"' EXIT

ARCHIVE_PATH="${TMP_DIR}/${ASSET_NAME}"
CHECKSUMS_PATH="${TMP_DIR}/dispatch_checksums.txt"

echo "==> Downloading ${ASSET_NAME}"
if [[ -n "${GITHUB_TOKEN:-}" ]]; then
  curl -fsSL -H "Authorization: Bearer ${GITHUB_TOKEN}" "${ASSET_URL}" -o "${ARCHIVE_PATH}"
else
  curl -fsSL "${ASSET_URL}" -o "${ARCHIVE_PATH}"
fi

if [[ -n "${CHECKSUMS_URL}" ]]; then
  echo "==> Verifying checksum"
  if [[ -n "${GITHUB_TOKEN:-}" ]]; then
    curl -fsSL -H "Authorization: Bearer ${GITHUB_TOKEN}" "${CHECKSUMS_URL}" -o "${CHECKSUMS_PATH}"
  else
    curl -fsSL "${CHECKSUMS_URL}" -o "${CHECKSUMS_PATH}"
  fi

  EXPECTED_SHA="$(awk -v file="${ASSET_NAME}" '$2 == file {print $1}' "${CHECKSUMS_PATH}" | head -n1)"
  if [[ -z "${EXPECTED_SHA}" ]]; then
    echo "Checksums file is missing ${ASSET_NAME}" >&2
    exit 1
  fi

  ACTUAL_SHA="$(sha256_file "${ARCHIVE_PATH}")"
  if [[ "${EXPECTED_SHA}" != "${ACTUAL_SHA}" ]]; then
    echo "Checksum mismatch for ${ASSET_NAME}" >&2
    echo "Expected: ${EXPECTED_SHA}" >&2
    echo "Actual:   ${ACTUAL_SHA}" >&2
    exit 1
  fi
else
  echo "No checksums asset found; skipping checksum verification."
fi

echo "==> Extracting archive"
tar -xzf "${ARCHIVE_PATH}" -C "${TMP_DIR}"
BINARY_PATH="$(find "${TMP_DIR}" -type f -name dispatch | head -n1)"
if [[ -z "${BINARY_PATH}" ]]; then
  echo "Archive did not contain 'dispatch' binary" >&2
  exit 1
fi

INSTALL_DIR="$(choose_install_dir)"
install_binary "${BINARY_PATH}" "${INSTALL_DIR}"

echo "Installed dispatch ${RELEASE_TAG} to ${INSTALL_DIR}/dispatch"
if [[ "${INSTALL_DIR}" == "${HOME}/.local/bin" ]]; then
  echo "Add to PATH if needed: export PATH=\"${HOME}/.local/bin:\$PATH\""
fi

"${INSTALL_DIR}/dispatch" --version || true
