#!/usr/bin/env bash

set -euo pipefail

ROOT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
PROJECT_ENV_FILE="${PROJECT_ENV_FILE:-$ROOT_DIR/.env}"
LFTP_ENV_FILE="${LFTP_ENV_FILE:-$ROOT_DIR/.env.lftp}"
MODE="${1:-all}"

usage() {
  cat <<'EOF'
Uso:
  bash ./scripts/lftp-sync.sh [all|files|storage|db]

Modos:
  all      Builda a aplicacao e envia frontend, backend, storage e dump opcional do banco.
  files    Builda a aplicacao e envia frontend e backend.
  storage  Envia apenas storage/uploads e storage/generated.
  db       Gera e envia apenas o dump do banco.

Variaveis esperadas em .env.lftp:
  LFTP_PROTOCOL, LFTP_HOST, LFTP_PORT, LFTP_USER, LFTP_PASSWORD
  REMOTE_WEB_DIR, REMOTE_API_DIR, REMOTE_STORAGE_DIR, REMOTE_DB_DUMPS_DIR

O dump do MySQL e opcional e depende de:
  SYNC_DB_DUMP=1
  MYSQL_HOST, MYSQL_PORT, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE
EOF
}

case "$MODE" in
  all|files|storage|db) ;;
  -h|--help|help)
    usage
    exit 0
    ;;
  *)
    echo "Modo invalido: $MODE" >&2
    usage
    exit 1
    ;;
esac

load_env_file() {
  local file_path="$1"
  if [[ -f "$file_path" ]]; then
    set -a
    # shellcheck disable=SC1090
    source "$file_path"
    set +a
  fi
}

require_command() {
  local command_name="$1"
  if ! command -v "$command_name" >/dev/null 2>&1; then
    echo "Comando obrigatorio ausente: $command_name" >&2
    exit 1
  fi
}

require_env() {
  local variable_name="$1"
  if [[ -z "${!variable_name:-}" ]]; then
    echo "Variavel obrigatoria ausente: $variable_name" >&2
    exit 1
  fi
}

upload_single_file() {
  local local_file="$1"
  local remote_dir="$2"
  local remote_name="${3:-}"

  if [[ ! -f "$local_file" ]]; then
    echo "Arquivo local nao encontrado: $local_file" >&2
    exit 1
  fi

  local file_name
  file_name="${remote_name:-$(basename "$local_file")}"

  lftp -u "${LFTP_USER},${LFTP_PASSWORD}" "${LFTP_PROTOCOL}://${LFTP_HOST}:${LFTP_PORT}" <<EOF
set cmd:fail-exit true
set net:max-retries 2
set net:timeout 20
set net:reconnect-interval-base 5
set xfer:clobber true
set ssl:verify-certificate no
mkdir -p $remote_dir
put -O $remote_dir -o $file_name $local_file
bye
EOF
}

mirror_directory() {
  local local_dir="$1"
  local remote_dir="$2"

  if [[ ! -d "$local_dir" ]]; then
    echo "Diretorio local nao encontrado: $local_dir" >&2
    exit 1
  fi

  lftp -u "${LFTP_USER},${LFTP_PASSWORD}" "${LFTP_PROTOCOL}://${LFTP_HOST}:${LFTP_PORT}" <<EOF
set cmd:fail-exit true
set net:max-retries 2
set net:timeout 20
set net:reconnect-interval-base 5
set xfer:clobber true
set mirror:parallel-directories true
set mirror:parallel-transfer-count ${LFTP_PARALLEL}
set ssl:verify-certificate no
mkdir -p $remote_dir
mirror -R --delete --verbose=3 --only-newer $local_dir $remote_dir
bye
EOF
}

build_application() {
  echo "==> Gerando build do frontend e backend"
  (
    cd "$ROOT_DIR"
    npm run build
  )
}

load_env_file "$PROJECT_ENV_FILE"
load_env_file "$LFTP_ENV_FILE"

LFTP_PROTOCOL="${LFTP_PROTOCOL:-sftp}"
LFTP_PORT="${LFTP_PORT:-22}"
LFTP_PARALLEL="${LFTP_PARALLEL:-4}"
SYNC_BUILD="${SYNC_BUILD:-1}"
SYNC_WEB="${SYNC_WEB:-1}"
SYNC_API="${SYNC_API:-1}"
SYNC_STORAGE="${SYNC_STORAGE:-1}"
SYNC_DB_DUMP="${SYNC_DB_DUMP:-0}"

if [[ -n "${DATABASE_URL:-}" && -z "${MYSQL_DATABASE:-}" ]]; then
  MYSQL_DATABASE="${DATABASE_URL##*/}"
  MYSQL_DATABASE="${MYSQL_DATABASE%%\?*}"
fi

MYSQL_HOST="${MYSQL_HOST:-127.0.0.1}"
MYSQL_PORT="${MYSQL_PORT:-3306}"
MYSQL_USER="${MYSQL_USER:-root}"

require_command lftp
require_command npm

require_env LFTP_HOST
require_env LFTP_USER
require_env LFTP_PASSWORD

if [[ "$MODE" == "all" || "$MODE" == "files" ]]; then
  require_env REMOTE_WEB_DIR
  require_env REMOTE_API_DIR
fi

if [[ "$MODE" == "all" || "$MODE" == "storage" ]]; then
  require_env REMOTE_STORAGE_DIR
fi

if [[ "$MODE" == "db" || "$SYNC_DB_DUMP" == "1" ]]; then
  require_env REMOTE_DB_DUMPS_DIR
  require_command mysqldump
  require_command gzip
  require_env MYSQL_DATABASE
fi

if [[ "$SYNC_BUILD" == "1" && ( "$MODE" == "all" || "$MODE" == "files" ) ]]; then
  build_application
fi

if [[ "$MODE" == "all" || "$MODE" == "files" ]]; then
  if [[ "$SYNC_WEB" == "1" ]]; then
    echo "==> Sincronizando frontend build para $REMOTE_WEB_DIR"
    mirror_directory "$ROOT_DIR/apps/web/dist" "$REMOTE_WEB_DIR"
  fi

  if [[ "$SYNC_API" == "1" ]]; then
    echo "==> Sincronizando backend build para $REMOTE_API_DIR"
    mirror_directory "$ROOT_DIR/apps/api/dist" "$REMOTE_API_DIR/dist"
    mirror_directory "$ROOT_DIR/apps/api/prisma" "$REMOTE_API_DIR/prisma"
    upload_single_file "$ROOT_DIR/apps/api/package.json" "$REMOTE_API_DIR"
    upload_single_file "$ROOT_DIR/package.json" "$REMOTE_API_DIR"
    if [[ -f "$ROOT_DIR/package-lock.json" ]]; then
      upload_single_file "$ROOT_DIR/package-lock.json" "$REMOTE_API_DIR"
    fi
  fi
fi

if [[ "$MODE" == "all" || "$MODE" == "storage" ]]; then
  if [[ "$SYNC_STORAGE" == "1" ]]; then
    echo "==> Sincronizando storage para $REMOTE_STORAGE_DIR"
    mkdir -p "$ROOT_DIR/storage/uploads" "$ROOT_DIR/storage/generated"
    mirror_directory "$ROOT_DIR/storage/uploads" "$REMOTE_STORAGE_DIR/uploads"
    mirror_directory "$ROOT_DIR/storage/generated" "$REMOTE_STORAGE_DIR/generated"
  fi
fi

if [[ "$MODE" == "db" || ( "$MODE" == "all" && "$SYNC_DB_DUMP" == "1" ) ]]; then
  timestamp="$(date +%Y%m%d-%H%M%S)"
  mkdir -p "$ROOT_DIR/.deploy/mysql"
  dump_file="$ROOT_DIR/.deploy/mysql/${MYSQL_DATABASE}_${timestamp}.sql.gz"

  echo "==> Gerando dump local do banco $MYSQL_DATABASE"
  if [[ -n "${MYSQL_PASSWORD:-}" ]]; then
    MYSQL_PWD="$MYSQL_PASSWORD" \
      mysqldump \
        --host="$MYSQL_HOST" \
        --port="$MYSQL_PORT" \
        --user="$MYSQL_USER" \
        --single-transaction \
        --quick \
        --routines \
        --triggers \
        "$MYSQL_DATABASE" | gzip -c >"$dump_file"
  else
    mysqldump \
      --host="$MYSQL_HOST" \
      --port="$MYSQL_PORT" \
      --user="$MYSQL_USER" \
      --single-transaction \
      --quick \
      --routines \
      --triggers \
      "$MYSQL_DATABASE" | gzip -c >"$dump_file"
  fi

  echo "==> Enviando dump para $REMOTE_DB_DUMPS_DIR"
  upload_single_file "$dump_file" "$REMOTE_DB_DUMPS_DIR"
fi

echo "==> Sincronizacao concluida"
