#!/usr/bin/env bash
# Zenith Native — instalador / actualizador (Pop!_OS, Ubuntu, Debian).
#
#   curl -fsSL https://zenith-music-pro.pages.dev/linux/install.sh | bash
#   curl -fsSL https://zenith-music-pro.pages.dev/linux/install.sh | bash -s -- --update
#   ./install.sh --local ./zenith-native_0.1.0_amd64.deb
#
set -euo pipefail

BASE_URL="${ZENITH_LINUX_BASE:-https://zenith-music-pro.pages.dev}"
CHANNEL="stable"
VERSION=""
LOCAL_DEB=""
UPDATE=0
DRY_RUN=0
APP_ID="zenith-native"
DEB_NAME_PREFIX="zenith-native"
# Un .deb real de Zenith Native pesa muchos MB; HTML/SPA fallback suele ser <200K.
MIN_DEB_BYTES=1048576

usage() {
  cat <<'EOF'
Zenith Native installer

  curl -fsSL https://zenith-music-pro.pages.dev/linux/install.sh | bash
  curl -fsSL …/linux/install.sh | bash -s -- --update
  bash install.sh --local ./file.deb

Options:
  --update            Reinstall latest stable
  --channel CHANNEL   stable|beta (default: stable)
  --version VER       Pin version
  --local FILE.deb    Install local package (dev)
  --dry-run           Print actions only
  --help
EOF
  exit 0
}

log()  { printf '\033[1;36m==>\033[0m %s\n' "$*"; }
ok()   { printf '\033[1;32m✓\033[0m %s\n' "$*"; }
err()  { printf '\033[1;31m✗\033[0m %s\n' "$*" >&2; exit 1; }
warn() { printf '\033[1;33m!\033[0m %s\n' "$*"; }

need_cmd() {
  command -v "$1" >/dev/null 2>&1 || err "Falta comando: $1"
}

# Debian .deb = archivo `ar` → primeros 8 bytes: 21 3c 61 72 63 68 3e 0a ("!<arch>\n")
is_real_deb() {
  local f="$1"
  [[ -f "$f" ]] || return 1
  local hex
  hex="$(od -An -tx1 -N8 "$f" 2>/dev/null | tr -d ' \n')"
  [[ "$hex" == "213c617263683e0a" ]]
}

assert_real_deb() {
  local f="$1"
  local sz
  sz="$(wc -c <"$f" | tr -d ' ')"
  if ! is_real_deb "$f"; then
    local head
    head="$(head -c 80 "$f" | tr -d '\0' || true)"
    err "El archivo descargado NO es un .deb Debian (magic inválido).
Tamaño: ${sz} bytes
Inicio: ${head}

Causas típicas:
  • Aún no hay artefacto Linux publicado (pending_artifact)
  • Cloudflare devolvió HTML (SPA/404) en lugar del paquete

Compila en Pop!_OS:
  cd linux/zenith-native && pnpm install && pnpm tauri:build
  ./packaging/install.sh --local src-tauri/target/release/bundle/deb/*.deb
Luego publica:
  ./packaging/publish-linux-release.sh <version> stable"
  fi
  if [[ "$sz" -lt "$MIN_DEB_BYTES" ]]; then
    err "El .deb pesa solo ${sz} bytes (< ${MIN_DEB_BYTES}). Parece incompleto o falso."
  fi
  if command -v dpkg-deb >/dev/null 2>&1; then
    dpkg-deb -I "$f" >/dev/null 2>&1 || err "dpkg-deb no puede leer el paquete (corrupto o falso)."
  fi
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --update) UPDATE=1; shift ;;
    --channel) CHANNEL="${2:-}"; shift 2 ;;
    --version) VERSION="${2:-}"; shift 2 ;;
    --local) LOCAL_DEB="${2:-}"; shift 2 ;;
    --dry-run) DRY_RUN=1; shift ;;
    --help|-h) usage ;;
    *) err "Opción desconocida: $1 (usa --help)" ;;
  esac
done

[[ "$(uname -s)" == "Linux" ]] || err "Este instalador solo soporta Linux."
ARCH="$(uname -m)"
case "$ARCH" in
  x86_64|amd64) ARCH_DIR="linux-x86_64"; DEB_ARCH="amd64" ;;
  aarch64|arm64) ARCH_DIR="linux-aarch64"; DEB_ARCH="arm64" ;;
  *) err "Arquitectura no soportada: $ARCH (x86_64 / aarch64)" ;;
esac

need_cmd curl
need_cmd mktemp
need_cmd head
need_cmd wc
need_cmd od
need_cmd tr

if [[ -n "$LOCAL_DEB" ]]; then
  [[ -f "$LOCAL_DEB" ]] || err "No existe: $LOCAL_DEB"
  DEB_FILE="$(realpath "$LOCAL_DEB")"
  log "Validando .deb local…"
  assert_real_deb "$DEB_FILE"
  VERSION="${VERSION:-local}"
else
  MANIFEST_URL="${BASE_URL}/releases/${ARCH_DIR}/update/${CHANNEL}.json"
  log "Consultando canal ${CHANNEL}…"
  if ! MANIFEST="$(curl -fsSL "$MANIFEST_URL" 2>/dev/null)"; then
    MANIFEST_URL="${BASE_URL}/releases/${ARCH_DIR}/update/latest.json"
    MANIFEST="$(curl -fsSL "$MANIFEST_URL")" || err "No se pudo leer manifiesto: $MANIFEST_URL"
  fi

  if printf '%s' "$MANIFEST" | grep -q '"pending_artifact"[[:space:]]*:[[:space:]]*true'; then
    err "Zenith Native v$(printf '%s' "$MANIFEST" | sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n1) aún no tiene .deb en la CDN (pending_artifact=true).

No hay nada que instalar todavía desde internet.

En Pop!_OS, genera el paquete y publícalo:
  cd linux/zenith-native
  pnpm install
  pnpm tauri:build
  ./packaging/publish-linux-release.sh 0.1.0 stable
  # desde la raíz del repo: pnpm website:deploy

O instala un .deb local:
  curl -fsSL ${BASE_URL}/linux/install.sh | bash -s -- --local ./ruta/al.deb"
  fi

  if [[ -z "$VERSION" ]]; then
    VERSION="$(printf '%s' "$MANIFEST" | sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n1)"
    [[ -n "$VERSION" ]] || err "Manifiesto sin version: $MANIFEST_URL"
  fi

  EXPECT_SHA="$(printf '%s' "$MANIFEST" | sed -n 's/.*"sha256"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n1 || true)"
  if [[ "$EXPECT_SHA" == "null" ]]; then EXPECT_SHA=""; fi

  CANDIDATES=(
    "${BASE_URL}/releases/${ARCH_DIR}/${DEB_NAME_PREFIX}_${VERSION}_${DEB_ARCH}.deb"
    "${BASE_URL}/releases/${ARCH_DIR}/ZenithNative-${VERSION}-${DEB_ARCH}.deb"
    "${BASE_URL}/releases/${ARCH_DIR}/ZenithNative.deb"
  )

  TMPDIR="$(mktemp -d)"
  trap 'rm -rf "$TMPDIR"' EXIT
  DEB_FILE="${TMPDIR}/${APP_ID}.deb"
  DOWNLOADED=0
  USED_URL=""

  for url in "${CANDIDATES[@]}"; do
    log "Probando $url"
    if [[ "$DRY_RUN" -eq 1 ]]; then
      ok "dry-run: descargaría $url"
      DOWNLOADED=1
      USED_URL="$url"
      break
    fi
    # -f falla en HTTP error; aún así Pages puede devolver 200 + HTML
    if ! curl -fsSL "$url" -o "$DEB_FILE"; then
      warn "HTTP falló: $url"
      continue
    fi
    if is_real_deb "$DEB_FILE"; then
      ok "Descargado ($(du -h "$DEB_FILE" | cut -f1)) desde $url"
      DOWNLOADED=1
      USED_URL="$url"
      break
    fi
    warn "Respuesta no es .deb (¿HTML?). Ignorando $url"
    rm -f "$DEB_FILE"
  done

  [[ "$DOWNLOADED" -eq 1 ]] || err "No hay .deb válido publicado para v${VERSION} (${ARCH_DIR}).
Manifiesto: $MANIFEST_URL

Compila y publica el artefacto, o usa --local."
  if [[ "$DRY_RUN" -eq 0 ]]; then
    assert_real_deb "$DEB_FILE"
    if [[ -n "$EXPECT_SHA" ]] && command -v sha256sum >/dev/null 2>&1; then
      GOT="$(sha256sum "$DEB_FILE" | awk '{print $1}')"
      [[ "$GOT" == "$EXPECT_SHA" ]] || err "SHA-256 no coincide.
  esperado: $EXPECT_SHA
  obtenido: $GOT
  url: $USED_URL"
      ok "SHA-256 verificado"
    fi
  fi
fi

if [[ "$DRY_RUN" -eq 1 ]]; then
  ok "dry-run OK — no se instaló nada"
  exit 0
fi

if command -v zenith-native >/dev/null 2>&1 && [[ "$UPDATE" -eq 0 ]]; then
  CUR="$(zenith-native --version 2>/dev/null || true)"
  warn "Ya hay una instalación (${CUR:-desconocida}). Usa --update para reemplazar."
fi

need_cmd sudo
need_cmd dpkg

log "Instalando Zenith Native v${VERSION:-local}…"
# No enmascarar fallos de dpkg con apt-get install -f (eso dejaba “éxito” falso).
if ! sudo dpkg -i "$DEB_FILE"; then
  warn "dpkg reportó dependencias rotas — intentando reparar…"
  sudo apt-get install -f -y || err "Falló la instalación del .deb."
  # Reintentar por si apt -f dejó el paquete a medias
  sudo dpkg -i "$DEB_FILE" || err "Falló dpkg -i tras apt-get install -f."
fi

# Confirmar que el binario existe
if ! command -v zenith-native >/dev/null 2>&1; then
  # Algunos .deb ponen el binario en /usr/bin/zenith-native
  if [[ -x /usr/bin/zenith-native ]]; then
    ok "Binario en /usr/bin/zenith-native"
  else
    err "El paquete se instaló pero 'zenith-native' no está en PATH.
Comprueba: dpkg -L zenith-native | head"
  fi
fi

# Actualizador en PATH (seguro con pipe: no usa BASH_SOURCE)
UPDATE_WRAPPER="/usr/local/bin/zenith-native-update"
WRAPPER_BODY=$(cat <<EOF
#!/usr/bin/env bash
set -euo pipefail
exec curl -fsSL ${BASE_URL}/linux/install.sh | bash -s -- --update
EOF
)
if [[ -w /usr/local/bin ]]; then
  printf '%s\n' "$WRAPPER_BODY" > "$UPDATE_WRAPPER"
  chmod +x "$UPDATE_WRAPPER"
elif command -v sudo >/dev/null 2>&1; then
  printf '%s\n' "$WRAPPER_BODY" | sudo tee "$UPDATE_WRAPPER" >/dev/null
  sudo chmod +x "$UPDATE_WRAPPER"
fi
[[ -x "$UPDATE_WRAPPER" ]] && ok "Actualizador: zenith-native-update"

ok "Zenith Native v${VERSION} instalado."
printf '\n  Lanza:  zenith-native\n  Update: zenith-native-update\n\n'
