#!/usr/bin/env bash
#
# Instalação compartilhada do ambiente React Native + Expo no Linux Mint.
# Execute diretamente como root: bash instalar-react-native-linux-mint.sh
#
# Instaladores opcionais que podem ficar ao lado deste script:
#   node-v*-linux-x64.tar.xz
#   node-v*-linux-arm64.tar.xz
#   android-studio*.tar.gz
#   commandlinetools-linux-*_latest.zip
#
# Se não encontrar um instalador local, o script tentará baixá-lo.
# Testado sintaticamente com Bash; a instalação real depende da rede,
# arquitetura e repositórios disponíveis na máquina.

set -Eeuo pipefail
umask 022

SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
LOG_FILE="/var/log/instalar-react-native-linux-mint.log"
NODE_DIR="/opt/node"
ANDROID_HOME="/opt/android-sdk"
ANDROID_STUDIO_DIR="/opt/android-studio"
ANDROID_GROUP="androiddev"
PROFILE_FILE="/etc/profile.d/react-native.sh"

mkdir -p /var/log
touch "$LOG_FILE"
chmod 0644 "$LOG_FILE"
exec > >(tee -a "$LOG_FILE") 2>&1

trap 'rc=$?; echo; echo "[ERRO] O script falhou na linha ${LINENO} (código ${rc}). Consulte ${LOG_FILE}."; exit "$rc"' ERR

info() { printf '\n\033[1;34m[INFO]\033[0m %s\n' "$*"; }
ok()   { printf '\033[1;32m[OK]\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33m[AVISO]\033[0m %s\n' "$*" >&2; }
die()  { printf '\033[1;31m[ERRO]\033[0m %s\n' "$*" >&2; exit 1; }

[[ "$(id -u)" -eq 0 ]] || die "Execute como root. Exemplo: bash instalar-react-native-linux-mint.sh"

if [[ -r /etc/os-release ]]; then
  # shellcheck disable=SC1091
  . /etc/os-release
else
  die "Não foi possível identificar o sistema operacional."
fi

[[ "${ID:-}" == "linuxmint" || "${ID_LIKE:-}" == *ubuntu* || "${ID:-}" == "ubuntu" ]] \
  || warn "Este script foi preparado para Linux Mint/Ubuntu; sistema detectado: ${PRETTY_NAME:-desconhecido}."

ARCH="$(dpkg --print-architecture 2>/dev/null || uname -m)"
case "$ARCH" in
  amd64|x86_64) NODE_ARCH="x64"; ANDROID_ARCH="x64" ;;
  arm64|aarch64) NODE_ARCH="arm64"; ANDROID_ARCH="arm64" ;;
  *) die "Arquitetura não suportada por este script: $ARCH" ;;
esac

command -v apt-get >/dev/null 2>&1 || die "Este script requer apt-get."
export DEBIAN_FRONTEND=noninteractive

info "Atualizando índices e instalando dependências do sistema..."
apt-get update
apt-get install -y --no-install-recommends \
  ca-certificates curl wget unzip zip xz-utils tar gzip git \
  python3 file build-essential pkg-config \
  openjdk-17-jdk \
  adb fastboot \
  libstdc++6 libc6 libgcc-s1 libncurses6 libz1 \
  libx11-6 libxext6 libxi6 libxrender1 libxtst6 libxt6 \
  libglib2.0-0 libnss3 libxkbcommon0 libxcomposite1 libxdamage1 \
  libxfixes3 libxrandr2 libgbm1 libasound2 libatk1.0-0 \
  libatk-bridge2.0-0 libgtk-3-0 libdrm2 libxcb1 libxcb-cursor0 \
  2>&1 || {
    warn "Algum nome de biblioteca pode não existir nesta versão do Mint; instalando o conjunto básico."
    apt-get install -y --no-install-recommends ca-certificates curl wget unzip zip xz-utils tar gzip git python3 file build-essential openjdk-17-jdk adb
  }

# Grupo para permitir que todos os usuários locais usem o SDK compartilhado.
if ! getent group "$ANDROID_GROUP" >/dev/null; then
  groupadd --system "$ANDROID_GROUP"
fi

# Inclui contas humanas comuns com diretório home. Contas de serviço são ignoradas.
info "Adicionando usuários com diretório pessoal ao grupo ${ANDROID_GROUP}..."
while IFS=: read -r username _ uid _ _ home shell; do
  if [[ "$uid" =~ ^[0-9]+$ ]] && (( uid >= 1000 )) && [[ "$home" == /home/* ]] && [[ -d "$home" ]]; then
    usermod -aG "$ANDROID_GROUP" "$username" || warn "Não foi possível adicionar $username ao grupo $ANDROID_GROUP."
  fi
done < /etc/passwd

# Instala Node.js LTS a partir de arquivo local, se houver; caso contrário baixa a versão LTS.
install_node() {
  local archive="" version="" base_url="https://nodejs.org/dist"
  local temp_dir="" index_json="" node_version="" node_file="" download_url=""

  shopt -s nullglob
  local candidates=("$SCRIPT_DIR"/node-v*-linux-"$NODE_ARCH".tar.xz)
  shopt -u nullglob

  if (( ${#candidates[@]} > 0 )); then
    archive="${candidates[0]}"
    info "Usando Node.js local: $(basename "$archive")"
  else
    info "Nenhum arquivo Node.js local encontrado; procurando a versão LTS mais recente."
    temp_dir="$(mktemp -d)"
    index_json="$temp_dir/index.json"
    curl -fL --retry 3 --connect-timeout 20 "$base_url/index.json" -o "$index_json"
    node_version="$(python3 - "$index_json" <<'PY'
import json, sys
with open(sys.argv[1], encoding="utf-8") as f:
    versions = json.load(f)
for item in versions:
    if item.get("lts") and item.get("version", "").startswith("v"):
        print(item["version"])
        break
PY
)"
    [[ -n "$node_version" ]] || die "Não foi possível localizar uma versão LTS do Node.js."
    node_file="node-${node_version}-linux-${NODE_ARCH}.tar.xz"
    download_url="${base_url}/${node_version}/${node_file}"
    archive="$temp_dir/$node_file"
    curl -fL --retry 3 --connect-timeout 20 "$download_url" -o "$archive"
  fi

  mkdir -p "$NODE_DIR"
  temp_dir="$(mktemp -d)"
  tar -xJf "$archive" -C "$temp_dir" --strip-components=1
  rm -rf "${NODE_DIR:?}/"*
  cp -a "$temp_dir/." "$NODE_DIR/"
  rm -rf "$temp_dir"
  chown -R root:root "$NODE_DIR"
  chmod -R a+rX "$NODE_DIR"
  ln -sfn "$NODE_DIR/bin/node" /usr/local/bin/node
  ln -sfn "$NODE_DIR/bin/npm" /usr/local/bin/npm
  ln -sfn "$NODE_DIR/bin/npx" /usr/local/bin/npx
  if [[ -x "$NODE_DIR/bin/corepack" ]]; then
    ln -sfn "$NODE_DIR/bin/corepack" /usr/local/bin/corepack
  fi
  ok "Node.js instalado em $NODE_DIR"
}
install_node

# Configura Java e variáveis globais para todos os logins.
JAVA_HOME_PATH="$(dirname "$(dirname "$(readlink -f "$(command -v javac)")")")"
cat > "$PROFILE_FILE" <<EOF
# Ambiente compartilhado React Native / Expo
export JAVA_HOME="${JAVA_HOME_PATH}"
export ANDROID_HOME="${ANDROID_HOME}"
export ANDROID_SDK_ROOT="\$ANDROID_HOME"
export PATH="/opt/node/bin:/opt/android-studio/bin:\$ANDROID_HOME/cmdline-tools/latest/bin:\$ANDROID_HOME/platform-tools:\$ANDROID_HOME/emulator:\$PATH"
EOF
chmod 0644 "$PROFILE_FILE"

# SDK Android compartilhado e gravável pelo grupo androiddev.
mkdir -p "$ANDROID_HOME"
chown -R root:"$ANDROID_GROUP" "$ANDROID_HOME"
chmod -R g+rwX "$ANDROID_HOME"
find "$ANDROID_HOME" -type d -exec chmod g+s {} +

# Instala Android Studio a partir de arquivo local ou URL oficial.
install_android_studio() {
  local archive="" temp_dir=""
  shopt -s nullglob
  local candidates=("$SCRIPT_DIR"/android-studio*.tar.gz "$SCRIPT_DIR"/android-studio*.tgz)
  shopt -u nullglob

  if (( ${#candidates[@]} > 0 )); then
    archive="${candidates[0]}"
    info "Usando Android Studio local: $(basename "$archive")"
  else
    info "Nenhum arquivo Android Studio local encontrado; tentando baixar o pacote oficial."
    if [[ "$ANDROID_ARCH" != "x64" ]]; then
      warn "O download automático do Android Studio foi omitido para ARM64. Coloque o arquivo compatível ao lado do script, se disponível."
      return 0
    fi
    archive="$(mktemp --suffix=.tar.gz)"
    if ! curl -fL --retry 2 --connect-timeout 20 \
      "https://redirector.gvt1.com/edgedl/android/studio/ide-zips/latest/android-studio-latest-linux.tar.gz" \
      -o "$archive"; then
      warn "Não foi possível baixar Android Studio automaticamente. O restante da instalação continuará."
      rm -f "$archive"
      return 0
    fi
  fi

  temp_dir="$(mktemp -d)"
  if ! tar -tzf "$archive" >/dev/null 2>&1; then
    warn "O arquivo $(basename "$archive") não parece ser um tar.gz válido; ignorando Android Studio."
    rm -rf "$temp_dir"
    return 0
  fi
  tar -xzf "$archive" -C "$temp_dir"
  local extracted
  extracted="$(find "$temp_dir" -mindepth 1 -maxdepth 2 -type d -name 'android-studio' -print -quit)"
  if [[ -z "$extracted" ]]; then
    extracted="$(find "$temp_dir" -mindepth 1 -maxdepth 2 -type d -name 'Android Studio' -print -quit)"
  fi
  if [[ -z "$extracted" ]]; then
    warn "Não foi localizada a pasta android-studio dentro do arquivo. Ignorando a instalação."
    rm -rf "$temp_dir"
    return 0
  fi
  rm -rf "$ANDROID_STUDIO_DIR"
  mv "$extracted" "$ANDROID_STUDIO_DIR"
  chown -R root:"$ANDROID_GROUP" "$ANDROID_STUDIO_DIR"
  chmod -R a+rX "$ANDROID_STUDIO_DIR"
  find "$ANDROID_STUDIO_DIR" -type d -exec chmod g+s {} +
  rm -rf "$temp_dir"
  ok "Android Studio instalado em $ANDROID_STUDIO_DIR"
}
install_android_studio

# Instala Android SDK command-line tools de um ZIP local ou baixa a versão Linux x64.
install_android_cmdline_tools() {
  local archive="" temp_dir="" tools_root="$ANDROID_HOME/cmdline-tools"
  shopt -s nullglob
  local candidates=("$SCRIPT_DIR"/commandlinetools-linux-*_latest.zip)
  shopt -u nullglob

  if (( ${#candidates[@]} > 0 )); then
    archive="${candidates[0]}"
    info "Usando Android command-line tools local: $(basename "$archive")"
  else
    if [[ "$ANDROID_ARCH" != "x64" ]]; then
      warn "As command-line tools do Android não serão baixadas automaticamente nesta arquitetura. Coloque um ZIP compatível ao lado do script."
      return 0
    fi
    info "Baixando Android SDK Command-line Tools oficiais..."
    archive="$(mktemp --suffix=.zip)"
    if ! curl -fL --retry 3 --connect-timeout 20 \
      "https://dl.google.com/android/repository/commandlinetools-linux-13114758_latest.zip" -o "$archive"; then
      # Tenta também uma versão anterior ainda publicada, caso a versão acima mude.
      if ! curl -fL --retry 3 --connect-timeout 20 \
        "https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip" -o "$archive"; then
        warn "Não foi possível baixar Android command-line tools. Você poderá instalá-las pelo Android Studio."
        rm -f "$archive"
        return 0
      fi
    fi
  fi

  temp_dir="$(mktemp -d)"
  if ! unzip -tq "$archive" >/dev/null 2>&1; then
    warn "O ZIP de command-line tools é inválido; ignorando."
    rm -rf "$temp_dir"
    return 0
  fi
  unzip -q "$archive" -d "$temp_dir"
  mkdir -p "$tools_root"
  rm -rf "$tools_root/latest"
  if [[ -d "$temp_dir/cmdline-tools" ]]; then
    mkdir -p "$tools_root/latest"
    cp -a "$temp_dir/cmdline-tools/." "$tools_root/latest/"
  else
    warn "Estrutura esperada cmdline-tools não encontrada no ZIP."
    rm -rf "$temp_dir"
    return 0
  fi
  rm -rf "$temp_dir"
  rm -f "$archive"
  chown -R root:"$ANDROID_GROUP" "$tools_root"
  chmod -R g+rwX "$tools_root"
  find "$tools_root" -type d -exec chmod g+s {} +
  ok "Android SDK command-line tools instaladas."
}
install_android_cmdline_tools

# Tenta instalar componentes SDK. Se o download das tools não ocorreu, não interrompe o restante.
SDKMANAGER="$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager"
if [[ -x "$SDKMANAGER" ]]; then
  info "Aceitando licenças Android SDK e instalando ferramentas básicas..."
  set +e
  yes | "$SDKMANAGER" --sdk_root="$ANDROID_HOME" --licenses >/dev/null 2>&1
  LICENSE_RC=$?
  set -e
  if (( LICENSE_RC != 0 )); then
    warn "Não foi possível aceitar todas as licenças automaticamente; revise-as como usuário."
  fi

  set +e
  "$SDKMANAGER" --sdk_root="$ANDROID_HOME" \
    "platform-tools" "platforms;android-35" "build-tools;35.0.0" "emulator" \
    2>&1
  SDK_RC=$?
  set -e
  if (( SDK_RC != 0 )); then
    warn "A instalação de alguns componentes SDK falhou. Abra o Android Studio e conclua pelo SDK Manager."
  fi
else
  warn "sdkmanager não está disponível. O Android SDK poderá ser concluído pelo Android Studio."
fi

# Ajusta permissões para uso compartilhado.
chown -R root:"$ANDROID_GROUP" "$ANDROID_HOME" 2>/dev/null || true
chmod -R g+rwX "$ANDROID_HOME" 2>/dev/null || true
find "$ANDROID_HOME" -type d -exec chmod g+s {} + 2>/dev/null || true

# Atalhos para o Android Studio.
if [[ -x "$ANDROID_STUDIO_DIR/bin/studio.sh" ]]; then
  ln -sfn "$ANDROID_STUDIO_DIR/bin/studio.sh" /usr/local/bin/android-studio
  mkdir -p /usr/local/share/applications
  cat > /usr/local/share/applications/android-studio.desktop <<EOF
[Desktop Entry]
Version=1.0
Type=Application
Name=Android Studio
Comment=IDE para desenvolvimento Android
Exec=${ANDROID_STUDIO_DIR}/bin/studio.sh
Icon=${ANDROID_STUDIO_DIR}/bin/studio.svg
Terminal=false
Categories=Development;IDE;
EOF
  chmod 0644 /usr/local/share/applications/android-studio.desktop
fi

# Verificação final.
info "Verificando versões instaladas..."
node --version || true
npm --version || true
java -version 2>&1 | head -n 3 || true
git --version || true
adb version 2>&1 | head -n 2 || true

cat <<EOF

============================================================
 INSTALAÇÃO CONCLUÍDA (com possíveis avisos acima)
============================================================
Node.js:        $NODE_DIR
Android SDK:    $ANDROID_HOME
Android Studio: $ANDROID_STUDIO_DIR
Grupo SDK:      $ANDROID_GROUP
Configuração:   $PROFILE_FILE
Log:            $LOG_FILE

IMPORTANTE:
1. Os usuários precisam sair da sessão e entrar novamente para receber
   o novo grupo ${ANDROID_GROUP} e as variáveis de ambiente.
2. Se Android Studio/SDK não tiver sido instalado, abra o Android Studio
   ou instale os arquivos oficiais ao lado deste script e execute-o novamente.
3. Para criar um app Expo como usuário comum:

   npx create-expo-app@latest MeuApp
   cd MeuApp
   npx expo start

4. Para testar em um celular Android, instale Expo Go no celular e leia
   o QR Code exibido pelo Expo.
5. Para usar um emulador, abra Android Studio e configure um dispositivo
   virtual no Device Manager.

Não execute npm/npx para criar projetos como root; use a conta de cada aluno.
============================================================
EOF
