#!/bin/bash
#-----------------------------------------------------------------------------
#PRIVATE PROPERTY NOTICE
#-----------------------------------------------------------------------------
#  _   ____    _                            ____                _   _
# (_) / ___|  | |__     __ _   _ __   ___  |  _ \    __ _    __| | (_)   ___
# | | \___ \  | '_ \   / _` | | '__| / _ \ | |_) |  / _` |  / _` | | |  / _ \
# | |  ___) | | | | | | (_| | | |   |  __/ |  _ <  | (_| | | (_| | | | | (_) |
# |_| |____/  |_| |_|  \__,_| |_|    \___| |_| \_\  \__,_|  \__,_| |_|  \___/
#
#This code, design, build scripts and documentation are the private property
#of the iShareRadio team. Unauthorized copying, distribution, modification,
#or use is strictly prohibited. Do not remove or alter this header.
#
#INTELLECTUAL PROPERTY OWNERS / CONTACTS:
#  - Michael Cook (michael@dtmc.ca)
#  - Alan Gordon (alang@akgordon.com)
#
#-----------------------------------------------------------------------------
#Copyright (c) 2025 iShareRadio. All rights reserved.
#-----------------------------------------------------------------------------
#
#  -----------------------------------------------------------------------------
#  PRIVATE PROPERTY NOTICE — iShareRadio / ISR Client
#  -----------------------------------------------------------------------------
#
# Install isr-client from the iShareRadio APT repository (Debian/Ubuntu/Raspberry Pi).
#
# Usage:
#   curl -fsSL https://releases.ishareradio.com/flex_client/install.sh | sudo bash
#   curl -fsSL https://releases.ishareradio.com/flex_client/install.sh | sudo bash -s -- releases
#   BRANCH=releases curl -fsSL https://releases.ishareradio.com/flex_client/install.sh | sudo -E bash
#
# Options:
#   BRANCH   APT suite selector (default: main). Also accepted as the first argument.
#            Supported: main, releases, release, stable, enterprise_model_1, em1
#            - main: latest main-line CI builds (prod flex_client)
#            - releases / release / stable: tagged stable releases (prod flex_client)
#            - enterprise_model_1 / em1: hub2 enterprise train (hub2/flex_client)
#
# Env:
#   ISR_RELEASES_BASE_URL  Override APT root (default depends on suite)
#
set -euo pipefail

PROD_RELEASES_BASE_URL="https://releases.ishareradio.com/flex_client"
HUB2_RELEASES_BASE_URL="https://releases.ishareradio.com/hub2/flex_client"
KEYRING_PATH="/usr/share/keyrings/ishareradio.gpg"
PACKAGE_NAME="isr-client"
SOURCES_GLOB="/etc/apt/sources.list.d/ishareradio-flex-client*.list"

log() { echo "[isr-client install] $*"; }
die() { echo "[isr-client install] ERROR: $*" >&2; exit 1; }

require_root() {
  if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then
    die "Run as root (e.g. curl ... | sudo bash)"
  fi
}

detect_arch() {
  local machine
  machine="$(uname -m)"
  case "$machine" in
    x86_64|amd64) echo "amd64" ;;
    aarch64|arm64) echo "arm64" ;;
    *) die "Unsupported CPU architecture: $machine (supported: amd64, arm64)" ;;
  esac
}

resolve_apt_suite() {
  local branch="${1:-main}"
  case "$branch" in
    main) echo "main" ;;
    releases|release|stable) echo "stable" ;;
    enterprise_model_1|em1) echo "enterprise_model_1" ;;
    *)
      die "Unsupported branch '$branch'. Use: main, releases (or release/stable), enterprise_model_1 (or em1)"
      ;;
  esac
}

default_releases_base_url() {
  local suite="$1"
  if [[ "$suite" == "enterprise_model_1" ]]; then
    echo "$HUB2_RELEASES_BASE_URL"
  else
    echo "$PROD_RELEASES_BASE_URL"
  fi
}

sources_list_path() {
  local suite="$1"
  case "$suite" in
    stable) echo "/etc/apt/sources.list.d/ishareradio-flex-client-stable.list" ;;
    enterprise_model_1) echo "/etc/apt/sources.list.d/ishareradio-flex-client-em1.list" ;;
    *) echo "/etc/apt/sources.list.d/ishareradio-flex-client.list" ;;
  esac
}

installed_package_version() {
  dpkg-query -W -f='${Version}' "$PACKAGE_NAME" 2>/dev/null || true
}

# Highest version offered by the target APT base URL (not merely apt Candidate).
# Candidate can still be an installed "newer" package from a removed repo/suite
# (e.g. 0.main.* vs 0.enterprise-model-1.*), so never trust Candidate alone.
expected_version_from_target_repo() {
  local base_url="$1"
  local version
  version="$(
    apt-cache madison "$PACKAGE_NAME" 2>/dev/null | awk -F'|' -v base="$base_url" '
      index($3, base) {
        gsub(/^[ \t]+|[ \t]+$/, "", $2)
        if ($2 != "" && $2 != "(none)") { print $2; exit }
      }
    '
  )"
  if [[ -z "$version" ]]; then
    return 1
  fi
  echo "$version"
}

# True if the given version is offered by our APT base URL.
version_from_target_repo() {
  local version="$1"
  local base_url="$2"
  apt-cache madison "$PACKAGE_NAME" 2>/dev/null | awk -F'|' -v ver="$version" -v base="$base_url" '
    {
      gsub(/^[ \t]+|[ \t]+$/, "", $2)
      if ($2 == ver && index($3, base) > 0) { found = 1; exit }
    }
    END { exit found ? 0 : 1 }
  '
}

remove_conflicting_sources() {
  local keep_path="$1"
  local path
  shopt -s nullglob
  for path in $SOURCES_GLOB; do
    if [[ "$path" != "$keep_path" ]]; then
      log "Removing conflicting APT source: $path"
      rm -f "$path"
    fi
  done
  shopt -u nullglob
}

configure_apt_source() {
  local sources_path="$1"
  local deb_line="$2"
  local keep_path="$sources_path"

  log "Configuring APT source at ${sources_path}..."
  echo "$deb_line" | tee "$sources_path" >/dev/null
  remove_conflicting_sources "$keep_path"
}

install_expected_version() {
  local expected="$1"
  local base_url="$2"
  local installed

  installed="$(installed_package_version)"
  if [[ -n "$installed" && "$installed" == "$expected" ]] && version_from_target_repo "$expected" "$base_url"; then
    log "Already at expected target version ${PACKAGE_NAME}=${expected} from ${base_url}"
    return 0
  fi

  if [[ -n "$installed" && "$installed" == "$expected" ]]; then
    log "Version ${expected} is installed but not from ${base_url}; reinstalling from target repo."
    DEBIAN_FRONTEND=noninteractive apt-get install -y --reinstall --allow-downgrades \
      "${PACKAGE_NAME}=${expected}"
    return 0
  fi

  if [[ -n "$installed" ]]; then
    log "Retargeting ${PACKAGE_NAME}: installed=${installed} expected=${expected}"
  else
    log "Installing ${PACKAGE_NAME}=${expected}"
  fi
  DEBIAN_FRONTEND=noninteractive apt-get install -y --allow-downgrades \
    "${PACKAGE_NAME}=${expected}"
}

verify_installed_version() {
  local expected="$1"
  local base_url="$2"
  local actual

  actual="$(installed_package_version)"
  if [[ -z "$actual" ]]; then
    die "Verification failed: ${PACKAGE_NAME} is not installed after apt install"
  fi
  if [[ "$actual" != "$expected" ]]; then
    die "Verification failed: expected ${PACKAGE_NAME}=${expected}, but dpkg reports ${actual}. apt 'already the newest version' is not sufficient when retargeting repos/suites."
  fi
  if ! version_from_target_repo "$actual" "$base_url"; then
    die "Verification failed: ${PACKAGE_NAME}=${actual} is installed, but apt policy does not show it coming from ${base_url}"
  fi
  log "Verified ${PACKAGE_NAME}=${actual} from ${base_url}"
}

# Package postinst skips enable/start under DEBIAN_FRONTEND=noninteractive; always
# enable and restart here so the newly installed binary replaces any old process.
ensure_isr_client_service_running() {
  if ! command -v systemctl >/dev/null 2>&1; then
    log "systemctl not found; skip systemd enable/restart"
    return 0
  fi
  if [[ ! -d /run/systemd/system ]]; then
    log "systemd not active; skip service restart"
    return 0
  fi

  systemctl daemon-reload || true
  if ! systemctl enable isr-client.service; then
    die "Failed to enable isr-client.service"
  fi
  if ! systemctl restart isr-client.service; then
    die "Failed to restart isr-client.service after package install"
  fi
  systemctl enable --now isr-client-updater.timer 2>/dev/null || true

  if ! systemctl is-active --quiet isr-client.service; then
    die "isr-client.service is not active after restart"
  fi
  log "isr-client.service is active (new package binary loaded)"
}

main() {
  local branch="${BRANCH:-${1:-main}}"
  local arch suite sources_path deb_line releases_base_url keyring_url
  local expected_version installed_before

  require_root

  if ! command -v apt-get >/dev/null 2>&1; then
    die "apt-get not found. This installer supports Debian/Ubuntu and Raspberry Pi OS only."
  fi

  for cmd in curl gpg awk dpkg-query apt-cache; do
    if ! command -v "$cmd" >/dev/null 2>&1; then
      die "Required command not found: $cmd"
    fi
  done

  arch="$(detect_arch)"
  suite="$(resolve_apt_suite "$branch")"
  releases_base_url="${ISR_RELEASES_BASE_URL:-$(default_releases_base_url "$suite")}"
  releases_base_url="${releases_base_url%/}"
  keyring_url="${releases_base_url}/apt/ishareradio-archive-keyring.gpg"
  sources_path="$(sources_list_path "$suite")"
  deb_line="deb [signed-by=${KEYRING_PATH} arch=${arch}] ${releases_base_url} ${suite} main"

  log "Installing isr-client (branch=${branch}, apt suite=${suite}, arch=${arch})"
  log "APT base: ${releases_base_url}"

  installed_before="$(installed_package_version)"
  if [[ -n "$installed_before" ]]; then
    log "Currently installed: ${PACKAGE_NAME}=${installed_before}"
  else
    log "Currently installed: (none)"
  fi

  log "Installing APT signing key..."
  curl -fsSL "$keyring_url" | gpg --dearmor -o "$KEYRING_PATH"
  chmod 644 "$KEYRING_PATH"

  configure_apt_source "$sources_path" "$deb_line"

  log "Updating package indexes..."
  apt-get update -qq

  if ! expected_version="$(expected_version_from_target_repo "$releases_base_url")"; then
    die "No ${PACKAGE_NAME} package offered by ${releases_base_url} suite '${suite}' (check APT indexes)"
  fi
  log "Expected version from target repo: ${PACKAGE_NAME}=${expected_version}"

  install_expected_version "$expected_version" "$releases_base_url"
  verify_installed_version "$expected_version" "$releases_base_url"
  ensure_isr_client_service_running

  log "Done. isr-client is installed and the systemd service is running."
  log "Status page: http://$(hostname -I 2>/dev/null | awk '{print $1}' || echo 'localhost'):8111"
}

main "$@"
