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

# Orange Pi Plus 2E / Armbian Bookworm build helper for fm-rds-tx
#
# Goals:
# - install build + runtime dependencies
# - install libiio / Pluto-related userspace bits
# - build fmrtx for Linux ARM
# - collect binary + shared libraries into dist/orangepi/
#
# Notes:
# - Linux Pluto build is libiio-first (`-tags pluto`).
# - SoapySDR is optional fallback/debug tooling, not the primary Pluto path.
# - Windows Pluto path remains separate and untouched by this script.
#
# Usage:
#   chmod +x scripts/orangepi-build-libiio.sh
#   ./scripts/orangepi-build-libiio.sh
#
# Optional env:
#   PREFIX=/opt/fm-rds-tx
#   DIST_DIR=dist/orangepi
#   GO_VERSION=1.22.12
#   SKIP_APT=1
#   SKIP_GO_INSTALL=1
#   BUILD_TAGS=pluto
#
# If you want to install the packaged result into a target directory:
#   PREFIX=/opt/fm-rds-tx ./scripts/orangepi-build-libiio.sh

SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
REPO_DIR="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
DIST_DIR="${DIST_DIR:-${REPO_DIR}/dist/orangepi}"
BUILD_DIR="${DIST_DIR}/build"
RUNTIME_DIR="${DIST_DIR}/runtime"
PREFIX="${PREFIX:-/opt/fm-rds-tx}"
GO_VERSION="${GO_VERSION:-1.22.12}"
BUILD_TAGS="${BUILD_TAGS:-pluto}"
ARCH="$(dpkg --print-architecture 2>/dev/null || true)"

log() {
  printf '\n[%s] %s\n' "$(date '+%H:%M:%S')" "$*"
}

need_cmd() {
  command -v "$1" >/dev/null 2>&1 || {
    echo "Missing required command: $1" >&2
    exit 1
  }
}

apt_install_if_missing() {
  local missing=()
  for pkg in "$@"; do
    if ! dpkg -s "$pkg" >/dev/null 2>&1; then
      missing+=("$pkg")
    fi
  done
  if ((${#missing[@]})); then
    log "Installing missing packages: ${missing[*]}"
    sudo apt-get install -y "${missing[@]}"
  fi
}

install_go() {
  if command -v go >/dev/null 2>&1; then
    log "Go already present: $(go version)"
    return
  fi

  if [[ "${SKIP_GO_INSTALL:-0}" == "1" ]]; then
    echo "go not found and SKIP_GO_INSTALL=1 set" >&2
    exit 1
  fi

  local go_arch
  case "$ARCH" in
    armhf) go_arch="armv6l" ;;
    arm64) go_arch="arm64" ;;
    amd64) go_arch="amd64" ;;
    *)
      echo "Unsupported architecture for automated Go install: $ARCH" >&2
      exit 1
      ;;
  esac

  local tarball="go${GO_VERSION}.linux-${go_arch}.tar.gz"
  local url="https://go.dev/dl/${tarball}"
  local tmp="/tmp/${tarball}"

  log "Installing Go ${GO_VERSION} for ${go_arch}"
  wget -O "$tmp" "$url"
  sudo rm -rf /usr/local/go
  sudo tar -C /usr/local -xzf "$tmp"
  export PATH="/usr/local/go/bin:${PATH}"

  if ! grep -q '/usr/local/go/bin' "$HOME/.profile" 2>/dev/null; then
    printf '\nexport PATH="/usr/local/go/bin:$PATH"\n' >> "$HOME/.profile"
  fi

  log "Go installed: $(/usr/local/go/bin/go version)"
}

resolve_lib() {
  local name="$1"
  local ldconfig_bin=""
  if command -v ldconfig >/dev/null 2>&1; then
    ldconfig_bin="$(command -v ldconfig)"
  elif [[ -x /sbin/ldconfig ]]; then
    ldconfig_bin="/sbin/ldconfig"
  elif [[ -x /usr/sbin/ldconfig ]]; then
    ldconfig_bin="/usr/sbin/ldconfig"
  fi

  if [[ -n "$ldconfig_bin" ]]; then
    "$ldconfig_bin" -p 2>/dev/null | awk -v lib="$name" '$1 == lib { print $NF; exit }'
    return 0
  fi

  find /lib /usr/lib /usr/local/lib -name "$name" 2>/dev/null | head -n 1
}

copy_lib_if_found() {
  local libname="$1"
  local path
  path="$(resolve_lib "$libname" || true)"
  if [[ -z "$path" ]]; then
    path="$(find /lib /usr/lib /usr/local/lib -name "$libname" 2>/dev/null | head -n 1 || true)"
  fi
  if [[ -n "$path" && -f "$path" ]]; then
    cp -Lv "$path" "$RUNTIME_DIR/lib/"
  else
    log "Library not found: $libname"
  fi
}

find_soapy_plugin_path() {
  local candidate=""

  if command -v SoapySDRUtil >/dev/null 2>&1; then
    candidate="$(SoapySDRUtil --info 2>/dev/null | awk -F': ' '/Search path:/ {print $2; exit}')"
    if [[ -n "$candidate" && -d "$candidate" ]]; then
      printf '%s\n' "$candidate"
      return 0
    fi
  fi

  for candidate in \
    /usr/local/lib/SoapySDR/modules0.8-3 \
    /usr/local/lib/SoapySDR/modules0.8 \
    /usr/lib/arm-linux-gnueabihf/SoapySDR/modules0.8-3 \
    /usr/lib/arm-linux-gnueabihf/SoapySDR/modules0.8 \
    /usr/lib/SoapySDR/modules0.8-3 \
    /usr/lib/SoapySDR/modules0.8
  do
    if [[ -d "$candidate" ]]; then
      printf '%s\n' "$candidate"
      return 0
    fi
  done

  return 1
}

copy_soapy_plugins_if_found() {
  local plugin_path
  plugin_path="$(find_soapy_plugin_path || true)"
  if [[ -n "$plugin_path" && -d "$plugin_path" ]]; then
    mkdir -p "$RUNTIME_DIR/soapy-modules"
    cp -Lv "$plugin_path"/* "$RUNTIME_DIR/soapy-modules/" 2>/dev/null || true
    printf '%s\n' "$plugin_path" > "$DIST_DIR/SOAPY_PLUGIN_PATH.txt"
    log "Copied Soapy plugins from: $plugin_path"
  else
    log "Soapy plugin path not found"
  fi
}

write_runner() {
  cat > "${DIST_DIR}/run-fmrtx.sh" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"

SYSTEM_LIB_DIRS="/usr/local/lib:/usr/lib:/usr/lib/arm-linux-gnueabihf:/lib:/lib/arm-linux-gnueabihf"
export LD_LIBRARY_PATH="${SCRIPT_DIR}/runtime/lib:${SYSTEM_LIB_DIRS}:${LD_LIBRARY_PATH:-}"

if [[ -d "${SCRIPT_DIR}/runtime/soapy-modules" ]]; then
  export SOAPY_SDR_PLUGIN_PATH="${SCRIPT_DIR}/runtime/soapy-modules:${SOAPY_SDR_PLUGIN_PATH:-}"
elif [[ -f "${SCRIPT_DIR}/SOAPY_PLUGIN_PATH.txt" ]]; then
  export SOAPY_SDR_PLUGIN_PATH="$(cat "${SCRIPT_DIR}/SOAPY_PLUGIN_PATH.txt"):${SOAPY_SDR_PLUGIN_PATH:-}"
fi

exec "${SCRIPT_DIR}/runtime/bin/fmrtx" "$@"
EOF
  chmod +x "${DIST_DIR}/run-fmrtx.sh"
}

write_install_helper() {
  cat > "${DIST_DIR}/install.sh" <<EOF
#!/usr/bin/env bash
set -euo pipefail
PREFIX="{1:-$PREFIX}"
sudo mkdir -p "\$PREFIX/bin" "\$PREFIX/lib"
sudo cp -v "${DIST_DIR}/runtime/bin/fmrtx" "\$PREFIX/bin/"
sudo cp -v ${DIST_DIR}/runtime/lib/* "\$PREFIX/lib/" 2>/dev/null || true
cat <<'EON'
Installed.
Run with e.g.:
  LD_LIBRARY_PATH=\$PREFIX/lib \$PREFIX/bin/fmrtx --help
EON
EOF
  # replace placeholder introduced to avoid accidental shell expansion confusion
  sed -i 's/{1:-/\${1:-/g' "${DIST_DIR}/install.sh"
  chmod +x "${DIST_DIR}/install.sh"
}

main() {
  need_cmd bash
  need_cmd uname
  need_cmd awk
  need_cmd sed
  need_cmd cp
  need_cmd mkdir
  need_cmd ldd

  mkdir -p "$BUILD_DIR" "$RUNTIME_DIR/bin" "$RUNTIME_DIR/lib"

  if [[ "${SKIP_APT:-0}" != "1" ]]; then
    log "Refreshing apt metadata"
    sudo apt-get update

    apt_install_if_missing \
      ca-certificates \
      curl \
      wget \
      git \
      build-essential \
      pkg-config \
      gcc \
      g++ \
      make \
      file \
      binutils \
      tar \
      xz-utils \
      libiio0 \
      libiio-dev \
      libusb-1.0-0 \
      libxml2 \
      libxml2-dev

    # Optional / best-effort packages. Not all repos expose them on every arch.
    sudo apt-get install -y soapysdr-tools libsoapysdr0.8 libsoapysdr-dev 2>/dev/null || true
    sudo apt-get install -y soapy-module-plutosdr 2>/dev/null || true
    sudo apt-get install -y iio-oscilloscope 2>/dev/null || true
    sudo apt-get install -y libusb-1.0-0-dev 2>/dev/null || true
  fi

  install_go
  need_cmd go

  export PATH="/usr/local/go/bin:${PATH}"
  export CGO_ENABLED=1
  export GOOS=linux

  case "$ARCH" in
    armhf)
      export GOARCH=arm
      export GOARM=7
      ;;
    arm64)
      export GOARCH=arm64
      ;;
    amd64)
      export GOARCH=amd64
      ;;
    *)
      echo "Unsupported architecture: $ARCH" >&2
      exit 1
      ;;
  esac

  log "Build environment"
  go version
  echo "ARCH=${ARCH} GOOS=${GOOS} GOARCH=${GOARCH:-} GOARM=${GOARM:-} CGO_ENABLED=${CGO_ENABLED}"

  log "Tidying modules"
  (cd "$REPO_DIR" && go mod tidy)

  log "Building fmrtx with Linux Pluto/libiio-first backend (tags: $BUILD_TAGS)"
  (cd "$REPO_DIR" && go build -v -tags "$BUILD_TAGS" -o "$RUNTIME_DIR/bin/fmrtx" ./cmd/fmrtx)

  log "Collecting runtime libraries"
  copy_lib_if_found "libiio.so.0"
  copy_lib_if_found "libSoapySDR.so.0.8"
  copy_lib_if_found "libusb-1.0.so.0"
  copy_lib_if_found "libxml2.so.2"
  copy_lib_if_found "libstdc++.so.6"
  copy_lib_if_found "libgcc_s.so.1"
  copy_lib_if_found "libm.so.6"
  copy_lib_if_found "libc.so.6"
  if [[ "$BUILD_TAGS" == *soapy* ]]; then
    copy_soapy_plugins_if_found
  else
    log "Skipping Soapy plugin copy (BUILD_TAGS=$BUILD_TAGS)"
  fi

  log "Writing helper scripts"
  write_runner
  write_install_helper

  log "Writing build manifest"
  cat > "${DIST_DIR}/BUILD-INFO.txt" <<EOF
fm-rds-tx Orange Pi build
========================
Date: $(date -Is)
Host: $(uname -a)
Repo: $REPO_DIR
Dist: $DIST_DIR
Architecture: $ARCH
Go: $(go version)

Build command:
  go build -tags $BUILD_TAGS -o runtime/bin/fmrtx ./cmd/fmrtx

Important note:
  Linux Pluto builds should prefer the native libiio path (`-tags pluto`).
  SoapySDR is optional fallback/debug infrastructure only.
  Windows Pluto handling is separate and intentionally untouched by this script.
EOF

  log "Binary info"
  file "$RUNTIME_DIR/bin/fmrtx" || true

  log "Dynamic dependencies of built binary"
  ldd "$RUNTIME_DIR/bin/fmrtx" || true

  if [[ "$BUILD_TAGS" == *soapy* ]]; then
    log "Wrapper self-test: fmrtx --list-devices"
    "${DIST_DIR}/run-fmrtx.sh" --list-devices || true
  else
    log "Wrapper self-test: fmrtx --print-config"
    "${DIST_DIR}/run-fmrtx.sh" --print-config || true
  fi

  log "Done. Artifacts are in: $DIST_DIR"
  cat <<EOF

Next steps:
  1. Copy/use: $DIST_DIR/runtime/bin/fmrtx
  2. Libraries are in: $DIST_DIR/runtime/lib/
  3. Launch via wrapper:
       $DIST_DIR/run-fmrtx.sh --help
  4. Install to target prefix:
       $DIST_DIR/install.sh $PREFIX

Reminder:
  Default Linux packaging now prefers the native libiio Pluto backend.
  Use BUILD_TAGS=soapy only when you explicitly want the Soapy path.
  Windows Pluto support is intentionally left on its separate path.
EOF
}

main "$@"
