#!/usr/bin/env bash
set -euo pipefail
ZIP="${1:-$(ls -1 /home/blancdigital/blanc-v*.zip 2>/dev/null | sort -V | tail -n1)}"
[ -n "$ZIP" ] && [ -f "$ZIP" ] || { echo "Envie o zip da versao (blanc-vNN.zip) para /home/blancdigital antes de continuar."; exit 1; }
echo "Usando $ZIP"
command -v pm2 >/dev/null || { echo "Execute no mesmo usuário em que pm2 status mostra o sistema."; exit 1; }
META=$(mktemp)
CONFIG=$(mktemp --suffix=.json)
chmod 600 "$META" "$CONFIG"
BUILD_DIR=""
trap 'rm -f "$META" "$CONFIG"; [ -z "$BUILD_DIR" ] || rm -rf "$BUILD_DIR"' EXIT
pm2 jlist > "$META"
node - "$META" "$CONFIG" <<'JS'
const fs=require('fs');
const processes=JSON.parse(fs.readFileSync(process.argv[2],'utf8'));
const matches=processes.filter(p=>['blanc','blanc-oficial'].includes(p.name));
if(matches.length!==1){console.error('Não foi possível identificar um único sistema oficial. Confira pm2 status.');process.exit(1);}
const p=matches[0], e=p.pm2_env;
const cwd=e.pm_cwd;
if(!cwd?.startsWith('/home/blancdigital/')||!fs.existsSync(cwd+'/.env')){console.error('Pasta ou .env do sistema não encontrado. Nenhuma alteração foi feita.');process.exit(1);}
const env={...(e.env||{})};
for(const k of ['PORT','NITRO_PORT','HOST','NITRO_HOST','NODE_ENV']) if(e[k]!=null) env[k]=e[k];
const text=fs.readFileSync(cwd+'/.env','utf8');
const port=env.NITRO_PORT||env.PORT||text.match(/^NITRO_PORT\s*=\s*["']?(\d+)/m)?.[1]||text.match(/^PORT\s*=\s*["']?(\d+)/m)?.[1]||3000;
fs.writeFileSync(process.argv[3],JSON.stringify({apps:[{name:p.name,cwd,script:cwd+'/app.cjs',env,exec_mode:'fork',instances:1}]}));
console.log(cwd+'\n'+p.name+'\n'+port);
JS
INFO=$(node -e 'const c=require(process.argv[1]).apps[0];console.log(c.cwd);console.log(c.name);console.log(c.env.NITRO_PORT||c.env.PORT||require("fs").readFileSync(c.cwd+"/.env","utf8").match(/^(?:NITRO_PORT|PORT)\s*=\s*["\x27]?(\d+)/m)?.[1]||3000)' "$CONFIG")
APP_DIR=$(printf '%s\n' "$INFO" | sed -n '1p')
APP_NAME=$(printf '%s\n' "$INFO" | sed -n '2p')
PORT=$(printf '%s\n' "$INFO" | sed -n '3p')
STAMP=$(date +%Y%m%d-%H%M%S)
BACKUP=/home/blancdigital/backups-blanc/atualizacao-$STAMP
mkdir -p "$BACKUP"
chmod 700 "$BACKUP"
[ ! -d "$APP_DIR/.output" ] || cp -a "$APP_DIR/.output" "$BACKUP/"
[ ! -f "$APP_DIR/app.cjs" ] || cp -a "$APP_DIR/app.cjs" "$BACKUP/"
printf 'Atualizando %s em %s. Backup: %s\n' "$APP_NAME" "$APP_DIR" "$BACKUP"
unzip -tq "$ZIP"
# Pacotes com fontes são compilados no próprio VPS antes de parar o app.
# O ambiente atual é preservado e nunca é incluído no pacote de atualização.
if unzip -Z1 "$ZIP" | grep '^source-blanc/package.json$' >/dev/null; then
  BUILD_DIR=$(mktemp -d /home/blancdigital/blanc-build-XXXXXX)
  chmod 700 "$BUILD_DIR"
  unzip -oq "$ZIP" 'source-blanc/*' -d "$BUILD_DIR"
  cp "$APP_DIR/.env" "$BUILD_DIR/source-blanc/.env"
  chmod 600 "$BUILD_DIR/source-blanc/.env"
  echo "Preparando a nova versão no servidor; o sistema atual continua ligado."
  node "$BUILD_DIR/source-blanc/deploy/cpanel/build-release.cjs"
  [ -f "$BUILD_DIR/source-blanc/.output/server/index.mjs" ] || { echo "Nova versão não compilada. Sistema atual preservado."; exit 1; }
fi
pm2 stop "$APP_NAME"
unzip -oq "$ZIP" -x 'source-blanc/*' -d "$APP_DIR"
if [ -n "$BUILD_DIR" ]; then
  rm -rf "$APP_DIR/.output"
  cp -a "$BUILD_DIR/source-blanc/.output" "$APP_DIR/"
fi
# Chaves enviadas no pacote: grava no .env e na config do PM2, depois apaga o arquivo.
if [ -f "$APP_DIR/chaves-blanc.env" ]; then
  node -e '
const fs=require("fs");const [envPath,keysPath,cfgPath]=process.argv.slice(1);
const keys={};for(const l of fs.readFileSync(keysPath,"utf8").split("\n")){const m=l.match(/^([A-Z0-9_]+)=(.*)$/);if(m&&m[2])keys[m[1]]=m[2];}
let t=fs.readFileSync(envPath,"utf8");
for(const [k,v] of Object.entries(keys)){const re=new RegExp("^"+k+"=.*$","m");t=re.test(t)?t.replace(re,k+"="+v):t.replace(/\n?$/,"\n")+k+"="+v+"\n";}
fs.writeFileSync(envPath,t);
const c=JSON.parse(fs.readFileSync(cfgPath,"utf8"));Object.assign(c.apps[0].env,keys);fs.writeFileSync(cfgPath,JSON.stringify(c));
console.log("Chaves atualizadas: "+Object.keys(keys).join(", "));
' "$APP_DIR/.env" "$APP_DIR/chaves-blanc.env" "$CONFIG"
  rm -f "$APP_DIR/chaves-blanc.env"
fi
pm2 delete "$APP_NAME"
pm2 start "$CONFIG"
# Montador de vídeos (ffmpeg): baixa ffmpeg próprio se o servidor não tiver e liga o processo blanc-video.
if [ -f "$APP_DIR/video-worker.cjs" ]; then
  if ! command -v ffmpeg >/dev/null && [ ! -x "$APP_DIR/bin/ffmpeg" ]; then
    echo "Baixando ffmpeg para o montador de vídeos..."
    mkdir -p "$APP_DIR/bin" && TMPF=$(mktemp -d) && \
    curl -fsSL https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz -o "$TMPF/f.tar.xz" && \
    tar -xJf "$TMPF/f.tar.xz" -C "$TMPF" && cp "$TMPF"/ffmpeg-*-static/ffmpeg "$TMPF"/ffmpeg-*-static/ffprobe "$APP_DIR/bin/" && chmod +x "$APP_DIR/bin/"* ; rm -rf "$TMPF"
  fi
  if command -v ffmpeg >/dev/null || [ -x "$APP_DIR/bin/ffmpeg" ]; then
    pm2 delete blanc-video >/dev/null 2>&1 || true
    pm2 start "$APP_DIR/video-worker.cjs" --name blanc-video --cwd "$APP_DIR" && echo "Montador de vídeos ligado (blanc-video)."
    sleep 3; pm2 logs blanc-video --lines 5 --nostream || true
  else
    echo "ATENÇÃO: não foi possível instalar o ffmpeg; o montador de vídeos ficou desligado."
  fi
fi
pm2 save
OK=0
for i in $(seq 1 20); do
  CODE=$(curl -s -o /dev/null -w '%{http_code}' "http://127.0.0.1:$PORT/login" || true)
  if [ "$CODE" = 200 ]; then OK=1; break; fi
  sleep 2
done
if [ "$OK" != 1 ]; then
  echo "O sistema não respondeu 200. Veja os logs; backup mantido em $BACKUP."
  pm2 logs "$APP_NAME" --lines 40 --nostream
  exit 1
fi
echo "Sistema local respondeu HTTP 200."
LOCAL=$(curl -fsS "http://127.0.0.1:$PORT/login" | grep -aoE '/assets/index-[A-Za-z0-9_-]+\.js' | head -1 || true)
PUBLIC=$(curl -fsS "https://app.blancdigital.com.br/login?atualizacao=$STAMP" | grep -aoE '/assets/index-[A-Za-z0-9_-]+\.js' | head -1 || true)
printf 'Arquivo local: %s\nArquivo público: %s\n' "$LOCAL" "$PUBLIC"
if [ -n "$LOCAL" ] && [ "$LOCAL" = "$PUBLIC" ]; then echo "Atualização confirmada no domínio."; else echo "Domínio ainda não confirmado: confira o proxy/cache antes de liberar para a equipe."; fi
pm2 status
